类成员中正确使用unique_ptr

14

我希望能够从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;
}

3
不需要使用std::move,因为裸指针无法移动。 - emlai
@tuple_cat 但这可以编译和运行得非常好 - Dumbo
@SaeidYazdani 不过你不需要它。最好使用 std::make_unique() - πάντα ῥεῖ
@πάνταῥεῖ 那么生成器函数的返回类型将是什么? - Dumbo
@SaeidYazdani std::unique_ptr<MyType> - πάντα ῥεῖ
3个回答

19

你的代码运行良好(虽然冗余的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()表达式的结果已经是rvalue。

6
请注意,此问题已标记为C++11,因此值得一提的是std::make_unique 直到C++14才被引入。 - eerorika

5

这是正确的用法吗?

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

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

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

这可以避免在初始化过程中抛出异常时,temp对象泄漏,并且使得工厂的用户更难意外泄漏返回的指针。

1

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

在头文件中。

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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接