10

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".

Benj
  • 31,668
  • 17
  • 78
  • 127
  • 2
    This is a duplicate of [Explicitly defaulted destructor disables default move constructor in a class](https://stackoverflow.com/questions/56968443/explicitly-defaulted-destructor-disables-default-move-constructor-in-a-class) (with a very similar answer). – Davis Herring Mar 20 '20 at 04:40

1 Answers1

8

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.

orlp
  • 112,504
  • 36
  • 218
  • 315
  • 1
    That suggests this page is wrong: https://en.cppreference.com/w/cpp/language/destructor where it says under trivial destructors: "The destructor is not user-provided (meaning, it is either implicitly declared, or explicitly defined as defaulted on its first declaration)" – Benj Sep 20 '19 at 09:27
  • 2
    @Benj Why? That just lists the conditions for a *trivial* destructor, not a *default* or an *implicitly-defined* one. And it talks about *user-provided* not *user-declared*, which is a subtle difference. Either way, it probably is fruitless to talk about specifics on the cppreference wiki to this level of detail, if you want to get really specific like this you should consult the standard directly. – orlp Sep 20 '19 at 09:29