为什么要在std :: vector :: push_back(T object)方法中构造对象时调用析构函数?

问题描述 投票:0回答:2

我在这里有这行:

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管理在析构函数中释放的资源。如果在复制对象时调用了析构函数,则资源将被释放并且对象变为无效,指向不再存在的资源。

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

c++ vector destructor stdvector
2个回答
3
投票

我希望可以构造SomeClass并将其移到向量的背面,而没有任何副本。

那会发生。

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

的确。那将是您传递给move构造函数的临时对象:

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

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

很明显,先构造SomeClass,然后将其复制到向量中。

好吧,已移动准确地说。尽管移动是一种复制形式。

我不想避免这种情况,而是将其构造为向量的一部分(或至少移至向量,以避免任何复制)。

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

someSTLVector.emplace_back(...);

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


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

如果析构函数释放了一些资源,则默认的move构造函数/赋值可能没有按照您希望它们执行的操作进行。参见五/三规则。


1
投票

被移动的对象仍然被破坏。因此,您的SomeClass可能已移到向量中(可以在move构造函数中添加std::cout <<消息进行验证),但随后也会被销毁。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.