An undefined value is storage whose contents have not been established by the program. In C++, reading an uninitialized built-in variable produces undefined behavior, even though the program may appear to run normally. section 8.11
Prevent undefined values by establishing state before first use:
- Initialize primitives with a literal, input, or another initialized variable. section 8.11
- Make constructors initialize every instance variable and establish the class invariant. section 8.11
- Require necessary arguments instead of allowing clients to initialize required state later. section 8.11
Listing 8.21 A class with an uninitialized built-in instance variable
class Person {
private:
std::string name; #1
int age; #2
public:
Person(const std::string& name) { this->name = name; } #3
void setAge(int age) { this->age = age; }
friend std::ostream& operator<<(std::ostream&, const Person&);
};
std::ostream& operator<<(std::ostream& o, const Person& p) {
o << p.name << " is " << p.age << " years old";
return o;
}
int main() {
Person joey("Joey");
std::cout << joey << '\n';
return 0;
}
Shows a Person object whose age is declared but never initialized before output, creating undefined behavior. section 8.11
Listing 8.22 A class that insists on arguments for every instance variable
class Person {
private:
std::string name;
int age;
public:
Person(const std::string& name, int age) :
name(name), age(age) {} #1
friend std::ostream& operator<<(std::ostream&, const Person&);
};
std::ostream& operator<<(std::ostream& o, const Person& p) {
o << p.name << " is " << p.age << " years old";
return o;
}
int main() {
Person joey("Joey", 27); #2
std::cout << joey << '\n';
return 0;
}
Replaces delayed setup with constructor arguments and an initializer list, ensuring name and age are initialized together. section 8.11
Validate while initializing
A constructor can pass age through a private validator in its initializer list, rejecting negative input before the object becomes usable.
