With the introduction of the C++11 standard, C++ gained the ability to explicitly define default and deleted functions, providing developers with more precise control over the implementation and usage of certain member functions. These additions improve the readability, robustness, and sustainability of code by enabling developers to clearly define the default behavior or restrict certain operations. C++ includes various explicitly defaulted and deleted functions, a few examples of which are:
1. Explicitly Defaulted Functions (= default)
a) The member's default functions are
If a programmer does not explicitly define a member function, C++ will generate default implementations for it. These include the move constructor, move assignment operator, default constructor, and copy constructor.
b) ‘= default’ syntax
By employing the = default syntax, programmers are able to request the compiler to generate a default implementation for a member function beginning from C++11.
class MyClass
{
public:
// Explicitly defaulted default constructor
MyClass() = default;
// Explicitly defaulted copy constructor
MyClass(const MyClass&) = default;
// Explicitly defaulted copy assignment operator
MyClass& operator=(const MyClass&) = default;
//
};
c) Use Cases
When the standard functionality offered by the compiler is suitable.
Improving code legibility by explicitly mentioning the intended default behavior.
d) Syntax
class MyClass
{
public:
// Defaulted constructor
MyClass() = default;
// Defaulted copy constructor
MyClass(const MyClass&) = default;
// Defaulted assignment operator
MyClass& operator=(const MyClass&) = default;
// Defaulted destructor
~MyClass() = default;
};
Example:
Let's consider an example to demonstrate the Explicitly Defaulted Functions (= default) in C++.
#include <iostream>
class MyClass
{
public:
// Default constructor explicitly defaulted
MyClass() = default;
// Copy constructor explicitly defaulted
MyClass(const MyClass& other) = default;
// Move constructor explicitly defaulted
MyClass(MyClass&& other) noexcept = default;
// Copy assignment operator explicitly defaulted
MyClass& operator=(const MyClass& other) = default;
// Move assignment operator explicitly defaulted
MyClass& operator=(MyClass&& other) noexcept = default;
// Destructor explicitly defaulted
~MyClass() = default;
// Custom member function
void customFunction()
{
std::cout << "Custom function called." << std::endl;
}
};
int main()
{
MyClass obj1;
// Calls default constructor
MyClass obj2(obj1);
// Calls copy constructor
MyClass obj3 = std::move(obj2);
// Calls move constructor
obj1 = obj3;
// Calls copy assignment operator
obj2 = std::move(obj3);
// Calls move assignment operator
obj1.customFunction();
// Calls custom member function
return 0;
}
Output:
Custom function called.
Explanation:
- Include Header
In order to display messages on the console using std::cout, it is necessary to include the standard input/output stream header in this line.
- Defining a Class
The class MyClass includes special member functions that have been explicitly defaulted: destructor, copy assignment operator, move assignment operator, default constructor, copy constructor, and move constructor.
When invoking the custom member function customFunction, a message will be displayed.
Within the
- Main function.
Three objects of type MyClass, such as obj1, obj2, and obj3 are created in the main method.
- The default constructor is used in the construction of obj1.
- obj1 is sent as a parameter to the copy constructor, which creates obj2.
- The move constructor is used to create obj3 with obj2 as an input.
- The value of obj3 is subsequently assigned to obj1 by calling the copy assignment operator.
- The value of std::move(obj3) is assigned to obj2 when the move assignment operator is used.
- Finally, an obj1, the custom member function customFunction is called, resulting in the console being printed with the message.
The illustration of explicitly defaulted special member functions, alongside the instantiation, duplication, and relocation of objects of the MyClass type, is presented in this code snippet. Additionally, it showcases how custom member functions can be invoked by class instances.
2. Deleted Functions
a) Preventing Function Usage
In certain scenarios, it may be advantageous to limit the utilization of specific functionalities such as copying and transferring objects.
b) ‘= delete’ Syntax
By introducing the = delete syntax in C++11, developers gained the ability to explicitly eliminate a member function to make it inaccessible. Any attempt to use a deleted function will result in a compilation error.
class NonCopyable
{
public:
// Deleted copy constructor
NonCopyable(const NonCopyable&) = delete;
// Deleted copy assignment operator
NonCopyable& operator=(const NonCopyable&) = delete;
//
};
c) Use Cases
There are scenarios where a class should avoid utilizing a specific function to prevent limitations like immutability or copying capabilities.
It is utilized to avoid unintended usage and enforce specific behavior.
d) Syntax
class NoCopyClass
{
public:
// Deleted copy constructor
NoCopyClass(const NoCopyClass&) = delete;
// Deleted copy assignment operator
NoCopyClass& operator=(const NoCopyClass&) = delete;
};
Example:
Let's consider an example to demonstrate the Removed Functions in C++.
#include <iostream>
class NoCopyClass
{
public:
// Default constructor
NoCopyClass()
{
std::cout << "Default constructor called." << std::endl;
}
// Delete the copy constructor
NoCopyClass(const NoCopyClass&) = delete;
// Delete the copy assignment operator
NoCopyClass& operator=(const NoCopyClass&) = delete;
void customFunction()
{
std::cout << "Custom function called." << std::endl;
}
};
int main()
{
NoCopyClass obj1;
// Calls the default constructor
// The following line will result in a compilation error
// NoCopyClass obj2 = obj1; // Error: copy constructor is deleted
// The following line will also result in a compilation error
// NoCopyClass obj3;
// obj3 = obj1; // Error: copy assignment operator is deleted
obj1.customFunction();
return 0;
}
Output:
Default constructor called.
Custom function called.
Explanation:
- Include header
To output messages to the console using std::cout, it is essential to include the standard input/output stream header in this line.
- Definition of a Class
The copy constructor and copy assignment operator are the two removed member functions of the NoCopyClass class, while customFunction serves as the default constructor.
After creating an object of the class, the default constructor displays a message.
There is a risk of a compilation error if the copy constructor and copy assignment operator are invoked as they have been deliberately removed (= deleted).
- Main Function
This function instantiates an object named obj1 of the NoCopyClass type, invokes the default constructor, and displays a message. It demonstrates that the copy constructor and copy assignment operator have been deleted to prevent compilation problems, as any attempts to create another object (obj2) using these methods have been intentionally disabled. Upon invoking customFunction on obj1, it confirms that non-deleted member functions are still operational.
In essence, this code introduces a class named NoCopyClass, where the copy constructor and copy assignment operator are intentionally eliminated to disallow object duplication. It demonstrates how omitted functions can control a class's functionality and pinpoint potential compilation challenges.
Advantages of Explicitly Defaulted and Deleted Functions in C++:
Some benefits of Explicitly Defaulted and Deleted Functions in C++ include:
1. Intent and Clarity
Specified Functions: Declaring a function's default value explicitly with = default enhances code readability by clearly indicating the deliberate use of the compiler-generated default behavior.
Deleted Functions: The utilization of the "= delete" specifier signifies the deliberate prohibition of specific operations. This practice improves code clarity by clearly articulating the restrictions imposed on particular functions.
2. Preventing Unintended Operations
Default Functions: Ensures that necessary actions are automatically executed when required. For example, specifying a default copy constructor signifies that the class is capable of being copied and that the default implementation is adequate.
Prohibiting specific operations through deleted functions helps prevent unintended or unsafe behaviors. For instance, eliminating the copy constructor and copy assignment operator can prevent accidental object duplication.
3. Preventing Resource leaks
Avoiding explicit deletion of functions helps prevent inadvertent sharing of resources and potential memory leaks, especially in scenarios where managing dynamically allocated memory is critical.
4. Compiler-Generated Code
Default functions: Relying on compiler-generated code can result in more optimized and efficient implementations. The compiler will generate code tailored for the specific class when default functions are employed.
Disabling certain functions explicitly prevents the automatic generation of default code for those operations, reducing the chances of unintended behavior.
5. Enforcing Constraints on Design
Eliminated Functions: They play a crucial role in upholding design limitations by restricting certain actions that could potentially breach class invariants or the designated purpose of the class.
6. Maintenance and Evolvability
When a function's default behavior is satisfactory, it streamlines code maintenance by eliminating the need for manual updates to these functions when making future changes to the class.
Eliminating functions: Clearly defining restrictions on specific operations aids in averting inadvertent utilization, thereby simplifying the long-term maintenance and progression of the codebase.
7. Documentation and Code Review
Documentation regarding the anticipated behavior of specific functions by default, aiding in code evaluation and fostering teamwork among developers.
Omitted Functions: Effectively outlines the limitations and boundaries, aiding developers in grasping the designated purpose and constraints of a class.
8. Safer Code
Eliminated Functions: It stops specific actions that may lead to memory leaks, runtime errors, or unpredictable behavior, ultimately aiding in the development of more secure code.
9. Ownership and Semantics
Deleted Functions: Serve the purpose of avoiding inadvertent sharing of resources or data, upholding ownership semantics. To ensure exclusive ownership, a class overseeing distinct resources may disable copy operations.
By defining the desired functionality of particular member functions and restricting unintended actions, explicitly defaulted and deleted functions in C++ aid in crafting clearer, more secure, and sustainable code. Additionally, they provide a powerful set of mechanisms for reinforcing design requirements and conveying the intended utilization of classes within a software application.