rogrammers have little control over the implicit declarations of the four canonical member functions. The compiler will not generate a default constructor for a class that has a user-declared copy-constructor. This frustrating state of affairs is about to change. The deleted and defaulted functions proposal provides a convenient mechanism for just this type of per-class customization. The following sections will show you how to use defaulted functions.
In certain cases, you need to define a default constructor manually, because the compiler will not implicitly-declare it. Not only is manual constructor definition tedious, it’s also not very efficient.
Use the new =default function specifier to make the compiler generate a member function that wouldn’t be generated otherwise.
Presenting the Problem
Suppose you’re designing a class that requires a user-defined copy constructor:
class C{public: C(const C& rhs);};
Later, when you try to create an object for this class, you get a compilation error:
C obj;//error: no default constructor exists for class CC * pc= new C; //same error
This kind of error can baffle even experienced programmers. Wasn’t the compiler supposed to implicitly declare a default constructor for class C? No, it wasn’t. When you declare a copy constructor in a class, the compiler doesn’t implicitly-declare a default constructor in that class. What if you want the compiler to generate a default constructor for you anyway? In C++03, there’s no way to override these language rules; you simply have to define the missing default constructor manually:
class C{public: C(const C& rhs); C() {} //manual definition of a default constructor};C obj; //OK
Not only is this tedious, the user-defined default constructor is often less efficient than the compiler’s implicitly-defined default constructor.
What a Difference a default Makes
C++09 offers a neat solution to this problem by extending the semantics to the keyword default. To force the compiler to generate a copy constructor for a class that wouldn’t normally get one, declare the default constructor like this:
class C{public: C(const C& rhs); C()=default;};
This way, the compiler will be forced to generate a default constructor for C.
Notice how elegantly this new feature extends the meaning of default, a keyword that already exists in C and C++. To make default‘s new role distinct from its traditional use in switch statements, defaulted functions now adopt pure virtual functions‘ =specifier notation. The =default function specifier can be added to any of the special member functions?not just the constructor.
Author’s Note: By mere coincidence, the word default is used in both default constructors and defaulted functions. Recall that a default constructor is simply a constructor that can be invoked with no arguments. To avoid confusion, I use the phrase “defaulted constructor” to refer to a constructor that is declared with the =default specifier. |
Destructors Unleashed
The C++ standard states clearly when the compiler will implicitly declare a destructor for a class and when it won’t. Here too, the rules don’t always meet your design goals. With the =default specifier you can override them.
Suppose you’re designing an interface for an asbtract pointing device:
struct Pointing_device_interface{ virtual bool onRightClick(Point xy)=0; virtual bool onDoubleClick(Point xy)=0; //.. virtual ~Pointing_device_interface();};
You must declare a virtual destructor for this class because otherwise, the compiler will implicitly declare a non-virtual destructor for it. Here’s the catch: after you declare a destructor (virtual or not), you must define it as well?even if it’s a dummy destructor:
Pointing_device_interface::~Pointing_device_interface(){}
In this example, you’re forced to manually define a dummy destructor simply because it must be virtual. As with the manual definition of a default constructor, a manual destructor?however trivial?is less efficient than an implicitly-defined one, and it imposes an unnecessary burden on the programmer. Ideally, you’d like to have the compiler generate a virtual destructor for you. Let’s see how C++09 defaulted functions get it done:
struct Pointing_device_interface{ virtual int onRightClick(Point xy)=0; virtual int onDoubleClick(Point xy)=0; //.. virtual ~Pointing_device_interface()=default;};
The compiler now implicitly defines a virtual destructor for Pointing_device_interface. The implicitly-defined destructor is as efficient as any implicitly-defined virtual destructor.
Remember, defaulted functions are only declared; you don’t define them. The compiler will automatically define them for you.
A Trivial Question
Defaulted functions solve two problems: they are more efficient than manual implementations and they free the programmer from the burden of defining those functions manually.
C++ makes a distinction between trivial and nontrivial special member functions. This distinction isn’t purely academic; a class that has one or more nontrivial special member functions isn’t a POD type. This raises another question: are defaulted functions trivial?
An inline defaulted function can be trivial. To qualify as trivial, a defaulted function must be identical to the function that the compiler would implicitly declare without the =default specifier. Additionally, the defaulted function must be inline. Consider:
struct S { inline S()=default;};
The defaulted constructor of S is trivial because the compiler would have implicitly-declared a trivial constructor for S by default:
struct S { //no user-declared canonical functions. Hence, S //has implicitly-declared trivial constructor, dtor etc.};
However, the following defaulted destructor isn’t trivial:
struct S { inline virtual ~S()=default;};
The defaulted destructor is inline, which is the first criterion for qualifying as trivial. However, this destructor is virtual, whereas the implicitly-declared destructor would have been non-virtual. Therefore, the defaulted destructor of S is not trivial.