简体   繁体   中英

Default move assignment calls destructor, copy assignment doesn't

I'm observing a strange behavior I don't quite understand with respect to destructors and (default) copy and move assignments.

Let's say I have a class B that has default everything and a class Test that has custom destructor, default copy assignment, and (potentially) default move assignment.

Then we create an instance of B , assign it to a variable, and replace with a new instance using assignment (where the right side is rvalue).

Two things seems weird to me and I can't see the reason for them in documentation.

  1. When Test doesn't have move assignment (thus its copy assignment is called) the destructor of T1 object isn't explicitely called. I assume that in this case the idiomatic thing to do is to clean the resources as part of the copy assignment . Why is it different when move assignment is there (and called), however? If its there the Test 's destructor is called explicitely (?by the operator).
  2. The documentation specifies that the other after move assignment can be left in whatever state. How come the destructor for T2's temporal rvalue (ie the right side of =B("T2") ) isn't called in case B's member doesn't have move assignment ?

Playground code: https://onlinegdb.com/S1lCYmkKOV

#include <iostream>
#include <string>

class Test
{
public:
    std::string _name;

    Test(std::string name) : _name(name) { }
    ~Test()
    {
        std::cout << "Destructor " << _name << std::endl;
    }
    Test& operator=(const Test& fellow) = default;
    //Test & operator= ( Test && ) = default;

};

class B {
public:
Test t;

B() : t("T0") {}

B(std::string n) : t(n) {}
};

int fce(B& b)
{
   std::cout << "b = B(T2)\n";
   b = B("T2");
   std::cout << "return 0\n";

   return 0;
}


int main() {
    B b("T1");
    std::cout << "fce call\n";
    fce(b);
    std::cout << "fce end " << b.t._name << std::endl;
}

Output with move:

fce call
b = B(T2)
Destructor T1
return 0
fce end T2
Destructor T2

Output without move:

fce call
b = B(T2)
Destructor T2
return 0
fce end T2
Destructor T2

Default move assignment calls destructor, copy assignment doesn't

Both assignments result in the destruction of a temporary B object, so the destructor is called.

replace with a new instance using assignment

Pedantic note: Assignment doesn't replace instances. The instance remains the same; the value of the instance is modified. This distinction may be subtle, but may also be relevant to your confusion.

When Test doesn't have move assignment (thus its copy assignment is called) the destructor of T1 object isn't explicitely called.

It's somewhat unclear what you mean by "T1 object". The variable b that you initialised with "T1" is destroyed. But when it is destroyed, it's value has previously been assigned to "T2" , so that's what the destructor inserts into cout . This happens in both move and copy cases, and this is the second Destructor TX line in the output.

Why is it different when move assignment is there (and called), however?

The difference is when the temporary object from the line b = B("T2") is destroyed. This is the first Destructor TX line in the output.

After copy assignment, this temporary will still hold the "T2" value, so that's what you see in the destructor.

After move assignment, the temporary is no longer guaranteed to contain "T2" , but rather it is left in a valid but unspecified state (as described in specification of std::string ), so output could be anything. In this case it happened to be "T1" . (Based on this result, we might make a guess that the move assignment operator of the string may have been implemented by swapping the internal buffers. This observation is not a guaranteed behaviour).

The documentation specifies that the other after move assignment can be left in whatever state. How come the destructor for T2's temporal rvalue (ie the right side of =B("T2")) isn't called in case B's member doesn't have move assignment?

The destructor of the temporary is called. The temporary simply is no longer in the state described by "contains "T2" " after it has been moved from.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM