gpt4 book ai didi

c++ - std::move 之后的僵尸对象

转载 作者:可可西里 更新时间:2023-11-01 15:59:32 26 4
gpt4 key购买 nike

我对使用 C++0x move 语义 move 对象之后的状态感到困惑。我的理解是,一旦一个对象被 move ,它仍然是一个有效的对象,但它的内部状态已经改变,因此当它的析构函数被调用时,没有资源被释放。

但如果我的理解是正确的, move 对象的析构函数应该仍然被调用。

但是,当我执行一个简单的测试时,这并没有发生:

struct Foo
{
Foo()
{
s = new char[100];
cout << "Constructor called!" << endl;
}

Foo(Foo&& f)
{
s = f.s;
f.s = 0;
}

~Foo()
{
cout << "Destructor called!" << endl;
delete[] s; // okay if s is NULL
}

void dosomething() { cout << "Doing something..." << endl; }

char* s;
};

void work(Foo&& f2)
{
f2.dosomething();
}

int main()
{
Foo f1;
work(std::move(f1));
}

这个输出:

Constructor called!
Doing something...
Destructor called!

注意析构函数只被调用一次。这表明我对这里的理解是错误的。为什么析构函数没有被调用两次?以下是我对应该发生的事情的解释:

  1. Foo f1 构造完成。
  2. Foo f1 被传递给 work,它采用右值 f2
  3. Foo 的 move 构造函数是调用, move f1 中的所有资源到 f2
  4. 现在 f2 的析构函数被调用,释放所有资源。
  5. 现在 f1 的析构函数被调用,这实际上并没有做任何事情因为所有资源都转移了到 f2。不过,析构函数是尽管如此。

但由于只调用了一个析构函数,因此第 4 步或第 5 步不会发生。我对析构函数进行了回溯,以查看它是从哪里调用的,它是从第 5 步开始调用的。那么,为什么不调用 f2 的析构函数呢?

编辑: 好吧,我修改了这个,所以它实际上是在管理资源。 (一个内部内存缓冲区。)尽管如此,我还是得到了析构函数只被调用一次的相同行为。

最佳答案

编辑 (新的正确答案)
抱歉,仔细查看代码,似乎答案要简单得多:你永远不会调用 move 构造函数。你永远不会真正 move 对象。您只需将右值引用传递给 work 函数,该函数在该引用上调用一个成员函数,它仍然指向原始对象。

原始答案,为后人保存

为了实际执行 move ,您必须在 work 中包含类似 Foo f3(std::move(f2)); 的内容。然后你可以在 f3 上调用你的成员函数,这是一个新对象,通过从 f

move 创建

据我所知,您根本没有理解 move 语义。您只是看到了普通的旧拷贝省略。

要进行 move ,您必须使用 std::move(或者具体来说,传递给构造函数的参数必须是未命名/临时的)右值引用,例如从 std::move 返回)。否则,它会被视为普通的老式左值引用,然后 应该 进行复制,但像往常一样,允许编译器优化它,留下一个正在构造的对象,还有一个对象被销毁。

无论如何,即使有 move 语义,编译器也没有理由不做同样的事情:只是优化 move ,就像它已经优化掉拷贝一样。 move 是便宜的,但是只在需要它的地方构造对象,而不是构造一个对象,然后将它 move 到另一个位置并在第一个位置调用析构函数,它仍然更便宜。

同样值得注意的是,您使用的是一个相对较旧的编译器,并且规范的早期版本对于这些“僵尸对象”应该发生什么非常不清楚。所以 GCC 4.3 可能只是不调用析构函数。我相信这只是最后一次修订,或者可能是之前的修订,明确要求调用析构函数

关于c++ - std::move 之后的僵尸对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4082065/

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