【问题标题】:Is it a bad habit to initialize a unique_ptr using reset?使用 reset 初始化 unique_ptr 是一个坏习惯吗?
【发布时间】:2016-03-16 15:15:19
【问题描述】:

当我需要一个类型为 std::unique_ptr 的数据成员时,我通常使用 std::unique::reset 来用新对象初始化这个 unique_ptr。

下面是一个简化的例子:

class A {
 public:
  void SetValue(int x) {
    data_.reset(new B(x));
  }

 private:
  std::unique_ptr<B> data_;
};

在代码审查中,一位审阅者提到这是一个坏习惯,并要求我尽可能不要使用重置。相反,他建议使用以下方法:

std::make_unique

或类似以下的模板函数:

template <typename T>
struct MakeUniqueResult {
  using scalar = std::unique_ptr<T>;
};
template <typename T, typename... Args>
typename internal::MakeUniqueResult<T>::scalar
MakeUnique(Args&&... args) {  
  return std::unique_ptr<T>(
      new T(std::forward<Args>(args)...));  
}

在上述情况下是否有一些特殊的原因可以避免使用 std::unique_ptr::reset ?

【问题讨论】:

  • 代码的下一次编辑可能会在调用new 和调用reset() 之间引入一些操作。在这一点上,仅仅是“难闻的气味”就成了问题。
  • 当您调用reset 时,您并未初始化。您正在更改已存在对象的状态。不初始化一个没用的未初始化对象是没有意义的。
  • @chris 这是标准习语的目的,make_unique&lt;&gt;
  • 尊敬的原始提问者:您应该将标签更改为 C++14 问题,因为 C++11 没有 make_unique
  • 投票重新开放。对于“在上述情况下是否有一些特殊原因可以避免使用 std::unique_ptr::reset ?”这一问题,有客观事实的答案?

标签: c++ c++14 unique-ptr


【解决方案1】:

在您的示例中,无论您使用 std::make_unique 还是 std::unique_ptr::reset 和 new 效果都是一样的。

但在更有趣的代码中,使用std::make_unique 解决了一些异常安全问题,这就是为什么你的代码审查员建议养成它的习惯。

考虑一下如果您尝试一次创建两个唯一指针会发生什么:

Frobnicate(std::unique_ptr<Foo>(new Foo), std::unique_ptr<Bar>(new Bar(3)));

编译器必须做大量工作来创建这两个参数,并且它在执行该工作的顺序上具有很大的灵活性。如果其中一个构造函数抛出异常,分配给另一个构造函数的内存可能会也可能不会被清理。

但是如果你使用std::make_unique:

Frobnicate(std::make_unique<Foo>(), std::make_unique<Bar>(3));

临时的 unique_ptrs 将立即拥有它们各自的对象,因此如果创建另一个对象引发异常,则能够清理它们。

为了异常安全,以及避免直接使用 new 和 delete 的一般准则,每次使用 std::make_unique 是一个好习惯。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    • 2012-03-10
    • 2018-10-15
    • 1970-01-01
    • 2023-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多