C++对象是否不会被std::moved?

4
我得到了以下代码:(代码现场:C++ Shell)
class Worker
{
public:
  Worker (std::string name):_name (name) {};

  Worker (const Worker & worker):_name (worker._name)
  {  std::cout << _name << " got copied!" << std::endl; }

  Worker (Worker && other):_name (other._name)
  {  std::cout << _name << " got moved!" << std::endl;  }

  ~Worker ()
  {  std::cout << _name << " got destroyed!" << std::endl;  }

  void changeName(std::string name)
  {  this->_name = name;  }

private:
  std::string _name;
};

class Factory
{
public:
  Factory ()
  {  std::cout << "Factory got created!" << std::endl;  }

   ~Factory ()
  {  std::cout << "Factory got destroyed!" << std::endl;  }

  void addWorker (Worker & worker)
  {  this->workers.push_back (std::move (worker));  }

  Worker & getLastWorker ()
  {  this->workers.back ();  }

private:
  std::vector < Worker > workers;
};

int main ()
{
  auto factory = std::make_unique < Factory > ();
  Worker w1 ("Bob");
  factory->addWorker (w1);
  Worker & workerRef = factory->getLastWorker ();
  //workerRef.changeName("Mary");

  return 0;
}

我有一个 Factory,它将其 Workers 存储在一个向量中。当我运行 main() 时,我会得到以下输出:

Factory got created!
Bob got moved!
Bob got destroyed!
Factory got destroyed!
Bob got destroyed!

我无法理解为什么 Bob got destroyed! 出现了两次,因为我认为 Worker w1Factory 中被移动到向量 workers 中。此外,如果您将 workerRef.changeName("Mary"); 注释掉,代码会崩溃,并显示 Segmentation fault

我已经使用 C++ 编程一个月了,但在这里真的很困难。我已经查找了一段时间,但找不到线索,所以任何帮助都是好的!


{btsdaf} - CB Bailey
{btsdaf} - DummySenior
4个回答

7
只有对象的内容会被移动(如果实现方式是这样,也可以只复制)。这并不意味着原始对象消失了,只是其值可能会改变。
你的示例在两个地方创建了两个对象:
  1. Worker w1 ("Bob");
  2. this->workers.push_back (std::move (worker));
第二个对象从第一个对象中窃取了内部内容(表面上看是这样),但第一个对象仍然存在。任何存活的对象都将在其生命周期结束时调用其析构函数(对于w1,它是在main关闭时)。

{btsdaf} - Gaurav Sehgal
2
{btsdaf} - StoryTeller - Unslander Monica
@GauravSehgal - 移动后的字符串的析构函数很可能只是测试指针是否为空,然后什么都不做。 - Bo Persson
{btsdaf} - Arne Vogel
{btsdaf} - Arne Vogel
显示剩余2条评论

5
你仍然有两个对象,一个在主函数中,一个在向量内部。
“移动”实际上并不移动对象,只是移动它的内容——至少在概念上(std::move只是一种类型转换)。 并不一定会移动任何东西,就像你的情况一样,“移动构造函数”表现得和复制构造函数完全一样。
如果你想要一个更 “移动式”的移动构造函数,你应该写成:_name(std::move(other._name)),这将使w1的名字为空。
崩溃的原因是你忘记在getLastWorker函数中写return了。 增加编译器的警告级别并注意它。

1

首先,你的移动构造函数并没有真正地“移动”任何东西,它只是复制了字符串。

当你将 Worker 推入向量中时,你仍然有两个 Worker 对象:一个在 main 函数中,另一个在向量内部。这两个对象都需要被销毁。


0

很简单:

一个空对象的析构函数也会被调用。

移动构造函数中,旧对象将其内容(特别是指针)转移到新对象中,并变为空对象,然后作为空对象在作用域结束时被销毁。

请注意,在移动构造函数之后,原始对象不应再称为Bob...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接