gpt4 book ai didi

c++ - 默认 move 赋值调用析构函数,复制赋值不调用

转载 作者:太空宇宙 更新时间:2023-11-04 15:56:48 26 4
gpt4 key购买 nike

我观察到一个奇怪的行为,我对析构函数和(默认)复制和 move 分配不太了解。

假设我有一个类 B,它具有默认的所有内容和一个类 Test,它具有自定义析构函数、默认复制赋值和(可能)默认 move 赋值。

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

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

  1. Test 没有 move 赋值(因此调用它的复制赋值)时,T1 对象的析构函数不会被显式调用.我假设在这种情况下,惯用的做法是清理资源作为 copy assignment 的一部分。但是,为什么当 move assignment 存在(并被调用)时会有所不同?如果它在那里,Test 的析构函数被显式调用(?由运算符(operator))。
  2. 文档指定 move 分配后的other 可以保留在任何状态。如果 B 的成员没有 move 赋值,为什么不调用 T2 的时间右值的析构函数(即 =B("T2") 的右侧) ?

Playground 代码: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;
}

带 move 的输出:

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

没有 move 的输出:

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

最佳答案

Default move assignment calls destructor, copy assignment doesn't

这两个赋值都会导致临时 B 对象的销毁,因此会调用析构函数。

replace with a new instance using assignment

迂腐的注解:赋值不会替换实例。实例保持不变;实例的值被修改。这种区别可能很微妙,但也可能与您的困惑有关。

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

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

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

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

复制赋值后,这个临时值仍将保存 "T2" 值,这就是您在析构函数中看到的。

move 赋值后,临时文件不再保证包含 "T2",而是保留在有效但未指定的状态(如 std::string 规范中所述) ), 所以输出可以是任何东西。在本例中,它恰好是 "T1"。 (基于这个结果,我们可能会猜测字符串的 move 赋值运算符可能是通过交换内部缓冲区实现的。这种观察结果不是保证的行为)。

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

临时的析构函数被调用。临时文件在 move 后不再处于“包含 “T2””描述的状态。

关于c++ - 默认 move 赋值调用析构函数,复制赋值不调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55376494/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com