【问题标题】:vector<unique_ptr> resizing with push_back - how does it work?vector<unique_ptr> 使用 push_back 调整大小 - 它是如何工作的?
【发布时间】:2013-04-14 23:26:48
【问题描述】:

据我了解,当将内容 push_back 放入向量时,有时它必须分配一个新的内存块,从而将所有元素从旧内存块复制到其中,调用它们的析构函数。由于 unique_ptr 析构函数删除了拥有的内存,它们怎么可能与向量一起使用? 在向量中使用 unique_ptr 是否安全? 是不是比普通指针慢?

【问题讨论】:

    标签: c++ memory vector c++11 smart-pointers


    【解决方案1】:

    根据cppreferencestd::unique_ptr 的用例之一是在“移动感知容器”中使用,例如std::vector。这意味着std::vector&lt;T&gt; 足够聪明,可以检测到T 何时可移动,std::unique_ptr 就是这种情况,并在调整向量大小时使用移动构造函数。

    【讨论】:

      【解决方案2】:

      使用移动语义可以将 unique_ptr 从一个位置移动到另一个位置。这将避免在指针使用std::move 从一个内存位置“移动”到另一个内存位置时破坏指针所保存的数据。

      这有点像在向量增长时从旧向量数组到新内存位置执行浅拷贝。

      【讨论】:

      • @RandyGual 毕竟 auto_ptr 也支持移动语义,它将对象的责任转移给新对象。因此,从这个意义上说,使用 auto_ptr 也应该是安全的。但我相信事实并非如此?
      【解决方案3】:

      导致将所有元素从旧内存块复制到其中,调用它们的析构函数。由于 unique_ptr 析构函数删除了拥有的内存,它们怎么可能与向量一起使用?

      事实上,它不再是严格地复制元素,它是移动。对于没有隐式或显式移动构造函数的类型,也是如此。但是对于unique_ptrs,这意味着新的unique_ptrs 是在新分配的内存中构造的,给定对“旧”unique_ptrs 的右值引用。他们的移动构造函数做了正确的事,即将所有权从旧的unique_ptrs 转移到新的unique_ptrs,让旧的为空,因此在销毁时不会删除任何内容。

      在向量中使用 unique_ptr 是否安全?

      只要您尊重语言规则和“C++ 常识”,使用unique_ptrs 无处不在 是省事。这意味着,您必须明确 做一些愚蠢的事情来破坏unique_ptrs 的安全行为。其中包括例如假装将拥有对象的所有权赋予另一个智能指针:

      unique_ptr<T> ptr1 {new T()};
      unique_ptr<T> ptr2 {ptr1.get()}; //two unique_ptr's owning the same object...
      

      或涉及reinterpret_castmemcpymemset 或其他不尊重 C++ 对象生命周期的破坏性操作。

      它比普通指针慢吗?

      也许吧。与复制原始指针(即将原始指针设置为零)相比,移动unique_ptr 显然会涉及一些小的开销。但是是否可以优化该开销取决于您的编译器和优化器。与以往一样,请咨询您的分析器以评估它是否变慢以及放慢是否重要。我打赌不会,考虑到智能指针会给你带来的安全性,永远不要询问unique_ptr 的性能。

      旁注:如果您事先知道向量的大小,请记住使用vector::reserve()。它将为您节省unique_ptrs 的重新分配和移动。如果你只知道你的向量的大概大小,不要小题大做——unique_ptrs 不是很大(通常和原始指针加上删除器一样大,可能会也可能不会优化掉),所以除非你真的有严格的内存限制,否则多保留几个百分点不会有什么坏处。

      【讨论】:

      • 因此,除非您确实有严格的内存限制,否则保留 100 个以上不会有什么坏处。 => 好吧,考虑到容器通常用于十几个元素,我更愿意给出一个以百分比表示的经验法则;多出 10%。
      • @MatthieuM。感谢您的反馈,我改写了那部分。
      • @Arne:如果我们可以在 vector 容器中使用 unique_ptr 那么为什么不使用 auto_ptr?毕竟 auto_ptr 也将对象的责任转移到新对象上。因此,从这个意义上说,使用 auto_ptr 也应该是安全的。但我相信事实并非如此?
      • @David:旧的auto_ptrs 的工作方式有点像unique_ptrs,因为它们转移了所有权。问题是他们在copying 时这样做,而unique_ptrmoving 时转移对象的所有权。这意味着使用auto_ptr,您可能会意外地创建指针的临时副本,将所有权转移给它,并在临时超出范围时删除对象。使用 unique_ptr 是不可能的,因为他们删除了 copy-ctor。因此,auto_ptr 自 C++11 以来已被弃用,unique_ptr 是更安全的完全替代品。
      猜你喜欢
      • 1970-01-01
      • 2017-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-21
      • 1970-01-01
      • 1970-01-01
      • 2010-11-12
      相关资源
      最近更新 更多