Benj
Benj

Reputation: 32428

Why is a "=default" destructor different than the implicitly declared destructor?

So I read this post:

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

Which discusses why:

~Widget() = default;

Isn't the same as:

~Widget() {}

However, it's also true that the "=default" case is different than the implicitly declared case. In some sense, =default doesn't actually give you the default, which is kinda odd.

Consider the following program:

class A
{
public:
    A(std::string str)
    {
        m_str = str;
    } 

    ~A() = default;

    A(A const& rhs)
    {
        printf("Got copied\n");
        m_str = rhs.m_str;
    }

    A(A&& rhs)
    {
        printf("Got moved\n");
        m_str = std::move(rhs.m_str);
    }

    std::string m_str;
};

class B 
{
public:
    B(std::string test) : m_a(test)
    {
    }

    ~B() = default;

    A m_a;
};

int main()
{
    B b("hello world");
    B b2(std::move(b));

    return 0;
}

Running this program will print "Got copied", unless you comment out the defaulted ~B() in which case it will print "Got moved". So why is this? I think "=default" is pretty confusing considering both this and the implicitly declared destructor are supposed to produce "trivial destructors".

Upvotes: 10

Views: 739

Answers (1)

orlp
orlp

Reputation: 118016

The implicitly-defined move constructor for B only gets created if

  • there are no user-declared copy constructors;
  • there are no user-declared copy assignment operators;
  • there are no user-declared move assignment operators;
  • there are no user-declared destructors;

Now when you say ~B() = default;, while you still get the default destructor, it's now also considered user-declared, and thus there won't be an implicitly defined move constructor.

Upvotes: 8

Related Questions