A constructor is a C++ member function that initializes an object when an instance of its class is created. Its central job is to establish a valid class invariant: every instance variable must receive a meaningful value before the object is used. section 7.2.2 section 8.11
Reliable constructors follow a few practical rules:
- Initialize every instance variable, either from constructor arguments or from a sensible default; leaving a built-in value uninitialized can produce undefined behavior. section 8.11
- Validate arguments while initializing members. If an argument would violate the invariant, reject construction rather than creating a partially valid object. section 7.3 section 10.2
- Prefer member initializer lists and in-class initializers for clear, direct initialization; default parameter lists become difficult to read across many constructors. section 2.5 section 8.11
- Avoid duplicating constructor behavior. Centralize shared initialization so overloads cannot diverge as the class changes. section 7.5
- Use =default when compiler-generated behavior is appropriate and =delete when construction-related operations must be unavailable. section 2.4
Reject invalid Person objects during construction
class Person { private: std::string name; int age; static int validateAge(int age) { if (age < 0) throw std::out_of_range("age must be non-negative"); return age; } public: Person(const std::string& name, int age) : name(name), age(validateAge(age)) {} }; Person joey("Joey", 27); // valid Person floyd("Floyd", -1); // construction fails The constructor does not create an object with an unknown or invalid age and hope that a later setter repairs it. It validates the argument during initialization and signals failure with an exception. section 8.11 section 10.2
Default constructors can be convenient, but they are dangerous when they allow incomplete state. Requiring essential arguments makes invalid instances harder to create. Constructors also interact with copying, moving, destruction, inheritance, and resource ownership, so changing one supplied member can affect which other members the compiler generates. section 2.4 section 8.1
Listing 2.8 A simple class with defaulted and deleted members
class Container {
private:
std::vector<int> values;
public:
Container() = default; #1
Container(const Container& o) : values(o.values) {}
Container& operator=(const Container& o) = delete; #2
void add(int n) { values.push_back(n); }
};
int main() {
Container c1;
c1.add(42);
Container c2(c1);
// c2 = c1; #3
return 0;
}
Compare a defaulted constructor, an explicitly defined copy constructor, and a deleted assignment operator in a small class. section 2.4








