如何避免std :: vector复制(重新)分配?

Zep*_*pee 5 c++ vector c++11

我刚刚std::vector在添加新元素时偶然发现了一个问题.

当您尝试向其添加更多元素时,它似乎需要分配更多空间,它通过复制来实现 最后一个元素 它目前拥有的所有元素.这似乎假设向量中的任何元素都是完全有效的,因此副本将始终成功.

在我们的例子中,这不一定是真的.目前我们可能在向量中有一些遗留元素,因为我们选择不删除它们,它们是有效对象,但它们的数据不保证有效行为.对象有防护,但我从未考虑过向复制构造函数添加防护,因为我认为我们永远不会复制无效对象(向量强制):

CopiedClass::CopiedClass(const CopiedClass& other)
    : member(other.member)
{
    member->DoSomething();
}
Run Code Online (Sandbox Code Playgroud)

碰巧当我们完成原始对象并将其留在向量中时,"成员"被置为空,所以当std :: vector尝试复制它时,它会崩溃.

是否可以防止std::vector复制该元素?或者我们是否必须防止可能的无效对象被复制?理想情况下,我们想继续假设只创建了有效的对象,但这似乎意味着我们立即将它们从向量中清除,而不是等待并在稍后阶段进行.

πάν*_*ῥεῖ 7

这实际上是你CopiedClass需要修复的设计缺陷.

std::vector 表现如预期和记录.

从你展示的小代码

member->DoSomething();
Run Code Online (Sandbox Code Playgroud)

这表明你将采用指针的浅表副本.

在我们的例子中,这不一定是真的.目前我们可能在向量中有一些遗留元素,因为我们选择不删除它们,它们是有效对象,但它们的数据不保证有效行为.


碰巧当我们完成原始对象并将其留在向量中时,"成员"被置为空,所以当std :: vector尝试复制它时,它会崩溃.

由于你的复制构造函数没有正确处理这种情况,因为遵循三条规则你的设计CopiedClass是错误的.

您应该关心创建您的深层副本member,还是使用智能指针(或纯实例成员),而不是原始指针.

智能指针应该正确处理这些成员的管理.

同样对于上面的代码片段,您应该nullpointer在盲目解除引用和调用之前进行测试DoSomething().

是否可以防止std::vector复制该元素?

至于你问这是可能的,但需要你永远不会改变向量的尺寸,并提供移动构造函数赋值操作符CopiedClass.

否则,std::vector 明确要求可复制类型(至少对于某些操作):

T必须满足CopyAssignableCopyConstructible的要求.

您有责任正确满足这些要求.


...它通过复制当前持有的最后一个元素来实现.

另请注意:在需要调整矢量大小的情况下,将复制所有现有元素,而不仅仅是您前提的最后一个元素.

  • 从C++ 11开始,可复制类型的要求仅适用于某些操作.否则,`std :: vector <std :: unique_ptr <X >>`是不可能的. (6认同)