Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is "=default" different from "{}" for default constructor and destructor?

People also ask

How is default constructor different from destructor?

Constructor helps to initialize the object of a class. Whereas destructor is used to destroy the instances.

What is the difference between the default no argument constructor and destructor?

Key Difference Between Constructors and DestructorsA constructor is allowed to accept the arguments as the arguments can be used to initialize the data members of the class. On the other hand, a destructor does not accept any arguments as its only work is to deallocate the memory of the object.

How is a default constructor defined?

A default constructor is a constructor that either has no parameters, or if it has parameters, all the parameters have default values. If no user-defined constructor exists for a class A and one is needed, the compiler implicitly declares a default parameterless constructor A::A() .

What is a default destructor?

The default destructor calls the destructors of the base class and members of the derived class. The destructors of base classes and members are called in the reverse order of the completion of their constructor: The destructor for a class object is called before destructors for members and bases are called.


This is a completely different question when asking about constructors than destructors.

If your destructor is virtual, then the difference is negligible, as Howard pointed out. However, if your destructor was non-virtual, it's a completely different story. The same is true of constructors.

Using = default syntax for special member functions (default constructor, copy/move constructors/assignment, destructors etc) means something very different from simply doing {}. With the latter, the function becomes "user-provided". And that changes everything.

This is a trivial class by C++11's definition:

struct Trivial
{
  int foo;
};

If you attempt to default construct one, the compiler will generate a default constructor automatically. Same goes for copy/movement and destructing. Because the user did not provide any of these member functions, the C++11 specification considers this a "trivial" class. It therefore legal to do this, like memcpy their contents around to initialize them and so forth.

This:

struct NotTrivial
{
  int foo;

  NotTrivial() {}
};

As the name suggests, this is no longer trivial. It has a default constructor that is user-provided. It doesn't matter if it's empty; as far as the rules of C++11 are concerned, this cannot be a trivial type.

This:

struct Trivial2
{
  int foo;

  Trivial2() = default;
};

Again as the name suggests, this is a trivial type. Why? Because you told the compiler to automatically generate the default constructor. The constructor is therefore not "user-provided." And therefore, the type counts as trivial, since it doesn't have a user-provided default constructor.

The = default syntax is mainly there for doing things like copy constructors/assignment, when you add member functions that prevent the creation of such functions. But it also triggers special behavior from the compiler, so it's useful in default constructors/destructors too.


They are both non-trivial.

They both have the same noexcept specification depending upon the noexcept specification of the bases and members.

The only difference I'm detecting so far is that if Widget contains a base or member with an inaccessible or deleted destructor:

struct A
{
private:
    ~A();
};

class Widget {
    A a_;
public:
#if 1
   virtual ~Widget() = default;
#else
   virtual ~Widget() {}
#endif
};

Then the =default solution will compile, but Widget won't be a destructible type. I.e. if you try to destruct a Widget, you'll get a compile-time error. But if you don't, you've got a working program.

Otoh, if you supply the user-provided destructor, then things won't compile whether or not you destruct a Widget:

test.cpp:8:7: error: field of type 'A' has private destructor
    A a_;
      ^
test.cpp:4:5: note: declared private here
    ~A();
    ^
1 error generated.

The important difference between

class B {
    public:
    B(){}
    int i;
    int j;
};

and

class B {
    public:
    B() = default;
    int i;
    int j;
};

is that default constructor defined with B() = default; is considered not-user defined. This means that in case of value-initialization as in

B* pb = new B();  // use of () triggers value-initialization

special kind of initialization that doesn't use a constructor at all will take place and for built-in types this will result in zero-initialization. In case of B(){} this won't take place. The C++ Standard n3337 § 8.5/7 says

To value-initialize an object of type T means:

— if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

— if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.

— if T is an array type, then each element is value-initialized; — otherwise, the object is zero-initialized.

For example:

#include <iostream>

class A {
    public:
    A(){}
    int i;
    int j;
};

class B {
    public:
    B() = default;
    int i;
    int j;
};

int main()
{
    for( int i = 0; i < 100; ++i) {
        A* pa = new A();
        B* pb = new B();
        std::cout << pa->i << "," << pa->j << std::endl;
        std::cout << pb->i << "," << pb->j << std::endl;
        delete pa;
        delete pb;
    }
  return 0;
}

possible result:

0,0
0,0
145084416,0
0,0
145084432,0
0,0
145084416,0
//...

http://ideone.com/k8mBrd