据我所知,当把东西推回到向量中时,有时它必须分配一个新的内存块,导致从旧内存块中复制所有元素,调用它们的析构函数。由于unique_ptr析构函数删除了拥有的内存,它们如何使用向量? 在向量中使用unique_ptr是否安全? 它比常规指针慢吗?
答案 0 :(得分:12)
导致从旧内存块中复制所有元素,调用它们的析构函数。由于unique_ptr析构函数删除了拥有的内存,它们如何使用向量?
事实上,它不再严格地复制元素,而是移动。对于没有隐式或显式移动构造函数的类型,它们是相同的。但是对于unique_ptr
来说,这意味着,在新分配的内存中构造新的unique_ptr
,给出对“旧”unique_ptr
的rvalue引用。他们的移动构造函数做了正确的事情,即它将所有权从旧的unique_ptr
转移到新的unique_ptr
,将旧版本留空,以便在销毁时不会删除任何内容。
在向量中使用unique_ptr是否安全?
只要您尊重语言规则和“C ++常识”,就可以节省使用unique_ptr
无处不在的。这意味着,你必须明确做愚蠢的事情来打破unique_ptr<T> ptr1 {new T()};
unique_ptr<T> ptr2 {ptr1.get()}; //two unique_ptr's owning the same object...
的安全行为。其中包括例如假装将拥有的对象的所有权赋予另一个智能指针:
reinterpret_cast
或涉及memcpy
,memset
,unique_ptr
或其他不尊重C ++对象生命周期的其他破坏性操作。
它比常规指针慢吗?
也许。与复制原始指针相比,移动unique_ptr
时显然会涉及一些小的开销,即将原始设置为零。但是,是否可以优化开销取决于您的编译器和优化器。与性能一样,请咨询您的探查器,以评估 是否更慢以及减速是否重要。我打赌它不会,并考虑到智能指针给你的安全性,从不问vector::reserve()
的性能。
旁注:如果您事先知道了矢量的大小,请记住使用unique_ptr
。它将为您节省unique_ptr
的重新分配和移动。如果你只知道你的向量将具有的近似大小,请不要小 - {{1}} s不是很大(通常与原始指针一样大以及删除器,可能会或可能不会被优化掉) ,所以保留几个百分点不会受到伤害,除非你真的有严格的内存限制。
答案 1 :(得分:6)
使用移动语义,可以将unique_ptr从一个位置移动到另一个位置。这样可以避免在std::move
从一个内存位置“移动”到另一个内存位置时指针保持的数据被破坏。
有点像向量增长时从旧向量数组到新内存位置执行浅拷贝。
答案 2 :(得分:3)
根据cppreference,std::unique_ptr
的一个用例用于“移动感知容器”,例如std::vector
。这意味着std::vector<T>
足够聪明,可以检测T
何时可移动,std::unique_ptr
就是这种情况,并在调整向量大小时使用移动构造函数。