【问题标题】:Correct usage of unique_ptr in class member在类成员中正确使用 unique_ptr
【发布时间】:2017-07-24 13:02:00
【问题描述】:

我正在尝试真正从 c++98 迁移到 c++11 及更高版本。我已经了解了大部分新内容,但我仍然不确定unique_ptr 的正确用法。

考虑下面的示例,其中类 A 有一个 unique_ptr 成员(我之前会使用原始指针!)。当用户需要时,应该通过在其他地方(不是类的一部分)调用函数来分配这个成员变量。这是正确的用法吗?如果没有,最好的选择是什么?

class A {
private:
   unique_ptr<MyType> mt;
public:
   void initStuff() {
      mt.reset(std::move(StaticFuncSomewhereElese::generateMyType()));
   } 
};

MyType* StaticFuncSomewhereElese::generateMyType() {
    MyType* temp = new MyType(...);
    //do stuff to temp (read file or something...)
    return temp;
}

【问题讨论】:

  • 那里不需要std::move,原始指针无法移动。
  • @tuple_cat 但是这个编译和运行完美无缺
  • @SaeidYazdani 不过你不需要它。而是使用std::make_unique()
  • @πάνταῥεῖ 那么生成器函数的返回类型是什么?
  • @SaeidYazdani std::unique_ptr&lt;MyType&gt;.

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


【解决方案1】:

您的代码运行良好(尽管可以省略冗余的* move),但最好尽早构造 unique_ptr

class A {
private:
   std::unique_ptr<MyType> mt;
public:
   void initStuff() {
      mt = StaticFuncSomewhereElese::generateMyType();
   } 
};

std::unique_ptr<MyType> StaticFuncSomewhereElese::generateMyType() {
    auto temp = std::make_unique<MyType>(…);
    // `make_unique` is C++14 (although trivially implementable in C++11).
    // Here's an alternative without `make_unique`:
    // std::unique_ptr<MyType> temp(new MyType(…));

    //do stuff to temp (read file or something...)
    return temp;
}

这样很明显generateMyType的返回值必须被调用者删除,内存泄漏的可能性较小(例如如果generateMyType提前返回)。

* move 是多余的,因为:

  1. 无法移动原始指针。
  2. generateMyType() 表达式的结果无论如何已经是一个右值。

【讨论】:

  • 请注意,该问题已标记为 C++11,因此值得一提的是 std::make_unique 直到 C++14 才引入。
【解决方案2】:

这是正确的用法吗?

除了std::move 是多余的,是的,这是正确的。这是多余的,因为 a) 裸指针被复制,无论它们是左值还是右值,b) 函数不返回引用,因此返回值已经是右值,因此无需转换。

但还有改进的余地。特别是,我建议从工厂函数返回一个唯一指针:

std::unique_ptr<MyType> StaticFuncSomewhereElese::generateMyType()

这可以防止 temp 在初始化引发异常时泄漏,并使工厂用户更难意外泄漏返回的指针。

【讨论】:

    【解决方案3】:

    为什么不让它成为一个通用的模板工厂?

    在标题中。

    template <typename T>
    std::unique_ptr<T> generateMyType();
    
    classss A {
    private:
       std::unique_ptr<MyType> mt;
       std::unique_ptr<MyOtherType> mot;
    public:
       void initStuff() {
          mt = generateMyType<MyType>();
          mot = generateMyType<MyOtherType>();
       } 
    };
    

    并且在源文件中

    template <typename T>
    std::unique_ptr<T> generateMyType()
    {
      auto temp = std::make_unique<T>();
      return temp;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-08-26
      • 2021-06-08
      • 1970-01-01
      • 2013-10-03
      • 2015-08-23
      • 1970-01-01
      • 1970-01-01
      • 2015-03-23
      • 1970-01-01
      相关资源
      最近更新 更多