默认移动分配调用析构函数,复制分配不

Pet*_*oll 0 c++ move

我正在观察关于析构函数以及(默认)复制和移动分配我不太了解的奇怪行为。

假设我有一个B具有默认所有内容的类Test,以及一个具有自定义析构函数,默认副本分配和(可能)默认移动分配的类。

然后,我们创建的实例B,将其分配给变量,然后使用赋值(其中右侧为rvalue)替换为新实例。

两件事对我来说似乎很奇怪,我在文档中看不到它们的原因。

  1. 如果Test没有move assignment(因此它的拷贝赋值被称为)的析构函数T1对象不明确地调用。我认为在这种情况下,惯常做法是将资源清理为的一部分copy assignment。但是,为什么在move assignment那里(被叫)时却有所不同呢?如果存在,则Test析构函数被显式调用(由运算符?)。
  2. 该文档指定other移动后分配可以保留为任何状态。=B("T2")如果B的成员没有T2的时间右值的析构函数(即的右侧),怎么不调用move assignment呢?

游乐场代码: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;
}
Run Code Online (Sandbox Code Playgroud)

带动输出:

fce call
b = B(T2)
Destructor T1
return 0
fce end T2
Destructor T2
Run Code Online (Sandbox Code Playgroud)

输出不动:

fce call
b = B(T2)
Destructor T2
return 0
fce end T2
Destructor T2
Run Code Online (Sandbox Code Playgroud)

eer*_*ika 5

默认移动分配调用析构函数,复制分配不

两种分配都会导致临时B对象的破坏,因此将调用析构函数。

使用赋值替换为新实例

书呆子注意:分配不会替换实例。实例保持不变;实例的值被修改。这种区别可能很微妙,但也可能与您的困惑有关。

当Test没有移动分配(因此将其复制分配称为)时,不会显式调用T1对象的析构函数。

不清楚“ T1对象”的含义。b初始化时使用的变量"T1"已销毁。但是,当销毁它时,它的值先前已分配给"T2",因此析构函数将其插入cout。在移动和复制情况下都会发生这种情况,这是Destructor TX输出中的第二行。

但是,当存在(并称为)移动分配时,为什么会有所不同?

区别在于线中的临时对象b = B("T2")被销毁时。这是Destructor TX输出中的第一行。

复制分配后,该临时"T2"变量仍将保留该值,因此您将在析构函数中看到该值。

在移动分配后,不再保证该临时对象包含"T2",而是将其保留为有效但未指定的状态(如的规范所述std::string),因此输出可以是任何内容。在这种情况下,它恰好是"T1"。(基于此结果,我们可能会猜测可能是通过交换内部缓冲区实现了字符串的移动赋值运算符。这种观察不能保证得到保证)。

该文档指定在移动后分配中的另一个可以保持任何状态。如果B的成员没有移动分配,怎么不调用T2的时间右值的析构函数(即= B(“ T2”)的右侧)?

临时的析构函数调用。临时文件"T2"从其移出后,不再只是处于“包含” 所描述的状态。