The new syntax "= default" in C++11
Categories:
Mastering C++11's = default
and = delete
for Special Member Functions

Explore the C++11 features = default
and = delete
to explicitly control the generation of special member functions, enhancing code clarity, safety, and performance.
Before C++11, the compiler would implicitly declare and define certain special member functions (default constructor, copy constructor, copy assignment operator, destructor) if you didn't declare them yourself. While convenient, this implicit behavior could sometimes lead to subtle bugs or prevent optimizations. C++11 introduced the = default
and = delete
specifiers, giving developers explicit control over these functions. This article delves into how these specifiers work, their benefits, and practical use cases.
Understanding Special Member Functions
Special member functions are a set of functions that the C++ compiler can automatically generate for a class. They are crucial for managing the lifetime and value semantics of objects. Prior to C++11, if you declared any constructor, the compiler would no longer generate a default constructor. Similarly, if you declared a copy constructor or copy assignment operator, the compiler would not generate the other. This 'all or nothing' rule often led to boilerplate code or unintended behavior.
flowchart TD A[Class Definition] --> B{Are Special Member Functions Declared?} B -->|No| C[Compiler Implicitly Declares/Defines] B -->|Yes| D{Are `= default` or `= delete` Used?} D -->|Yes, = default| E[Compiler Generates Default Implementation] D -->|Yes, = delete| F[Function is Deleted, Usage is Compile-Time Error] D -->|No, Custom Implementation| G[User-Defined Implementation Used] C --> H[Object Creation/Manipulation] E --> H G --> H
Flowchart illustrating compiler behavior for special member functions before and after C++11.
The = default
Specifier
The = default
specifier explicitly tells the compiler to generate the default implementation for a special member function. This is particularly useful when you've declared other constructors (which would suppress the implicit default constructor) but still want the compiler-generated default. It makes your intent clear and avoids writing an empty function body, which might prevent certain optimizations or trigger warnings.
class MyClass {
public:
// User-defined constructor
MyClass(int val) : value(val) {}
// Explicitly default the default constructor
// Without this, the compiler would not generate one
MyClass() = default;
// Explicitly default the copy constructor
MyClass(const MyClass&) = default;
// Explicitly default the copy assignment operator
MyClass& operator=(const MyClass&) = default;
// Explicitly default the destructor
~MyClass() = default;
private:
int value;
};
int main() {
MyClass obj1; // Uses defaulted default constructor
MyClass obj2(10); // Uses user-defined constructor
MyClass obj3 = obj2; // Uses defaulted copy constructor
obj1 = obj3; // Uses defaulted copy assignment operator
return 0;
}
Using = default
for various special member functions.
= default
is more than just syntactic sugar for an empty function body. It signals to the compiler that you want the compiler-generated version, which can have specific properties (e.g., triviality) that a user-defined empty function might not.The = delete
Specifier
Conversely, the = delete
specifier explicitly tells the compiler that a function should not be generated or used. Any attempt to call a deleted function will result in a compile-time error. This is invaluable for preventing unwanted operations, such as copying objects that manage unique resources (e.g., std::unique_ptr
), or ensuring a class is purely move-only. It's also useful for preventing implicit type conversions by deleting specific overloads.
class NonCopyable {
public:
NonCopyable() = default;
// Explicitly delete copy constructor and copy assignment operator
// This makes objects of NonCopyable non-copyable
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
// Move constructor and assignment can still be defaulted or custom-defined
NonCopyable(NonCopyable&&) = default;
NonCopyable& operator=(NonCopyable&&) = default;
};
class NoHeapAllocation {
public:
// Prevent heap allocation by deleting operator new
void* operator new(size_t) = delete;
void operator delete(void*) = delete;
NoHeapAllocation() = default;
};
int main() {
NonCopyable nc1;
// NonCopyable nc2 = nc1; // Compile-time error: call to deleted copy constructor
// nc1 = nc2; // Compile-time error: call to deleted copy assignment operator
NoHeapAllocation nha;
// NoHeapAllocation* p_nha = new NoHeapAllocation(); // Compile-time error: call to deleted operator new
return 0;
}
Using = delete
to prevent copying and heap allocation.
The Rule of Zero, Three, and Five
The = default
and = delete
specifiers simplify the 'Rule of Three/Five' to the 'Rule of Zero'.
- Rule of Three (pre-C++11): If you define a destructor, copy constructor, or copy assignment operator, you should define all three.
- Rule of Five (C++11 onwards): If you define any of the Rule of Three functions, you should also consider defining the move constructor and move assignment operator.
- Rule of Zero (C++11 onwards): If your class does not manage any resources directly (e.g., raw pointers, file handles), then you don't need to declare any of the special member functions. The compiler-generated versions will do the right thing. If your class does manage resources, encapsulate them in a class that follows the Rule of Zero (e.g.,
std::unique_ptr
,std::vector
), and then your class can also follow the Rule of Zero.
graph TD A[Does Class Manage Resources Directly?] -->|No| B[Rule of Zero: No Special Members Needed] A -->|Yes| C[Encapsulate Resource in RAII Wrapper] C --> D[Wrapper Follows Rule of Zero/Five] D --> B
Decision flow for applying the Rule of Zero.
By explicitly defaulting or deleting special member functions, you communicate your design intent clearly to both the compiler and other developers. This leads to more robust, maintainable, and often more performant C++ code.