【问题标题】:Why is the destructor called upon construction of an object in std::vector::push_back(T object) method?为什么在 std::vector::push_back(T object) 方法中构造对象时调用析构函数?
【发布时间】:2020-06-05 09:53:09
【问题描述】:

我这里有这行:

someSTLVector.push_back(SomeClass(...));

我希望 SomeClass 将被构造并移动到向量的后面,没有任何副本。然而,析构函数在这里被调用。我尝试用std::move 修改它:

someSTLVector.push_back(std::move(SomeClass(...)));

但结果没有改变。

我还尝试在SomeClass 中定义以下内容:

SomeClass(SomeClass&&) = default;
SomeClass& operator= (SomeClass&&) = default;
SomeClass(const SomeClass&) = delete;
SomeClass& operator= (const SomeClass&) = delete;

这也没有帮助,析构函数仍然被调用。请注意,SomeClass 包含一个引用作为成员

很明显SomeClass 被构造然后复制到向量中。我不想避免这种情况,并将其构建为向量的一部分(或至少移动到向量,避免任何复制)。 SomeClass 管理在析构函数中释放的资源。如果在复制对象时调用析构函数,则资源被释放,对象变为无效,指向不再存在的资源。

如何实例化一个类,在该类中生成的对象将被放置在向量的后面,但在此过程中不被复制(并因此被销毁)?

【问题讨论】:

  • 这是XY problemstd::vector 没有任何问题。您的问题是您的默认移动构造函数没有做正确的事情。你必须要么删除它,要么定义它来做正确的事情。
  • 没错,但我确实提供了足够的信息让人们了解实际需要做什么。
  • 问题是回答明确说明的问题只会解决实际描述的问题的症状。使用emplace_back 将避免这种特定的移动/复制,但是如果移动构造函数没有以正确的语义定义,则该类仍然被破坏并且向量将偶尔失败。因此,答案将需要考虑回答明确的问题以及(不相关的)潜在问题。最好直接询问根本问题。

标签: c++ vector destructor stdvector


【解决方案1】:

我希望 SomeClass 将被构造并移动到向量的后面,没有任何副本。

确实会发生这种情况。

但是,这里调用了析构函数。

确实如此。那将是您传递给移动构造函数的临时对象:

someSTLVector.push_back(SomeClass(...));
                        ^^^^^^^^^^^^^^

有用于初始化临时对象的语法。

很明显 SomeClass 被构造然后复制到向量中。

嗯,移动确切地说。虽然搬家是一种复制。

我不想避免这种情况,并将其构建为向量的一部分(或至少移动到向量,避免任何复制)。

您已经设法避免复制。为避免移动,您可以使用emplace_back 成员函数而不是push_back

someSTLVector.emplace_back(...);

这会将参数直接转发给元素的构造函数。


如果在复制对象时调用析构函数,则资源被释放,对象变为无效,指向不再存在的资源。

如果你的析构函数释放了一些资源,那么默认的移动构造函数/赋值可能没有做你希望他们做的事情。参见五/三规则。

【讨论】:

    【解决方案2】:

    移动的对象仍然被破坏。所以你的SomeClass 可能被移动到向量中(你可以在你的移动构造函数中添加一个std::cout << 消息来验证)但它也会被破坏。

    您可以调用std::vector::emplace_back 将项目直接构建到向量中。但是,这仍然不能保证您的对象不会被移动(例如,如果向量需要增长,它可以分配更多空间,然后将所有对象移动到新存储,然后在其原始位置销毁它们)。

    如果您在析构函数中释放了一些资源,则需要确保在对象被移动时不会释放。通常将构造函数“清空”移出移动对象(例如,在该方法中给定SomeClass(SomeClass&& other),您将修改other 为“清空它”)。然后您的析构函数可以查看它是否“空”(已被移出)并且不会释放您持有的任何资源。

    【讨论】:

      猜你喜欢
      • 2020-04-05
      • 1970-01-01
      • 2012-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多