std :: move和unique_ptr :: reset之间有什么区别?

hhb*_*lly 10 c++ unique-ptr c++11

对于std::unique_ptrs p1p2,std::move()和之间有什么区别std::unique_ptr::reset()

p1 = std::move(p2);

p1.reset(p2.release());
Run Code Online (Sandbox Code Playgroud)

Jon*_*ely 17

从[unique.ptr.single.assign]/2中标准的移动分配规范中可以明显看出答案:

效果:将所有权转移u*this好像通过调用reset(u.release())后跟一个赋值std::forward<D>(u.get_deleter()).

显然移动分配不一样,reset(u.release())因为它做了额外的事情.

附加效果很重要,如果没有它,您可以使用自定义删除器获得未定义的行为:

#include <cstdlib>
#include <memory>

struct deleter
{
  bool use_free;
  template<typename T>
    void operator()(T* p) const
    {
      if (use_free)
      {
        p->~T();
        std::free(p);
      }
      else
        delete p;
    }
};

int main()
{
  std::unique_ptr<int, deleter> p1((int*)std::malloc(sizeof(int)), deleter{true});
  std::unique_ptr<int, deleter> p2;
  std::unique_ptr<int, deleter> p3;

  p2 = std::move(p1);  // OK

  p3.reset(p2.release());  // UNDEFINED BEHAVIOUR!
}
Run Code Online (Sandbox Code Playgroud)


Pup*_*ppy 5

例如,第一个能够警告您是否存在析构函数不匹配.另外,这release()是一个非常危险的功能,你的琐碎的例子是正确的,但许多其他用途不是.最好永远不要使用这个功能.

  • 如果删除者不匹配,那么第一个删除者不仅能够发出警告,它将拒绝编译.这是一件好事 (4认同)
  • @Ali由于`reset`没有任何先决条件,你可以随时调用它,因为任何移动被指定为将对象移动到**未定义但有效的**状态,这使得任何函数的使用都没有前置条件永远有效.它只是在依赖某些前提条件时(比如指针是`nullptr`,但是甚至可以保证标准的`std :: unique_ptr`),这要求你首先检查相应的条件.移动不会以任何方式使对象无效,这是一种常见的误解. (3认同)
  • @Ali:这是非常危险的,因为基本上你可以用返回值做的唯一安全的事情是把它放回另一个`unique_ptr <T,Del>`.事实上,任何其他事情都会导致删除程序不匹配,内存泄漏或双重删除等问题. (3认同)
  • @Ali在任何移动之后,保证对象处于有效但不确定的状态.std :: unique_ptr进一步保证在移动之后它将是一个空指针. (2认同)