Undefined behavior is an operation whose result or behavior the applicable language standard does not define. The compiler may produce unpredictable results, crashes, security vulnerabilities, or remove the operation during optimization. section 1.2.1
Treat undefined behavior as a correctness failure, even when a program appears to work. Common causes include reading uninitialized data, deleting a derived object through a base pointer without a virtual destructor, and returning a pointer or reference to a local object. section 8.11 section 8.8 section 11.4
Prevent undefined behavior by making object state and lifetime explicit:
- Initialize every built-in member before its first use; make constructors establish the class invariant rather than relying on later setter calls. section 8.11 section 7.3
- Require meaningful constructor arguments and validate them during initialization, such as rejecting a negative age. section 8.11 section 7.3
- Give a polymorphic base class a virtual destructor before deleting derived objects through base pointers. section 8.8
- Return locally computed objects by value instead of exposing pointers or references whose storage ends when the function returns. section 11.4
A lifetime error that looks successful
A catenate function that returns a reference to its local combined string may print the expected message if the memory remains untouched, but accessing that reference is unsafe after the function ends. Returning std::string by value produces a correct result; modern compilers may minimize copying through return value optimization. section 11.4
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;
}
Inspect the Person example to see how an uninitialized built-in member can survive compilation and appear to work until it is read. section 8.11






