为什么在C++ 17中使用std :: make_unique?

Ete*_*nal 86 c++ unique-ptr c++17

据我所知,引入了C++ 14 std::make_unique,因为由于没有指定参数评估顺序,这是不安全的:

f(std::unique_ptr<MyClass>(new MyClass(param)), g()); // Syntax A
Run Code Online (Sandbox Code Playgroud)

(说明:如果评估首先为原始指针分配内存,则g()std::unique_ptr构造之前抛出调用和异常,然后内存泄漏.)

呼叫std::make_unique是一种约束呼叫顺序的方法,从而使事情变得安全:

f(std::make_unique<MyClass>(param), g());             // Syntax B
Run Code Online (Sandbox Code Playgroud)

从那以后,C++ 17澄清了评估顺序,使得Syntax A也安全,所以这里是我的问题:在C++ 17中仍然有理由使用std::make_uniqueover std::unique_ptr的构造函数吗?你能举一些例子吗?

截至目前,我能想象的唯一原因是它只允许输入MyClass一次(假设您不需要依赖多态std::unique_ptr<Base>(new Derived(param))).但是,这似乎是一个非常弱的原因,特别是当构造函数std::make_unique不允许指定删除器时std::unique_ptr.

而且为了清楚起见,我并不是主张std::make_unique从标准库中删除(至少为了向后兼容而保持它有意义),而是想知道是否仍然存在强烈倾向于它的情况std::unique_ptr

Nat*_*ica 66

你找对主要原因是对的.仍然没有使用新的指南,并且它的输入原因较少(不必重复类型或使用单词new).不可否认,这些都不是强有力的论据,但我真的不喜欢new在我的代码中看到.

也不要忘记一致性.你绝对应该使用,make_shared所以使用make_unique是自然的,适合模式.然后改变std::make_unique<MyClass>(param)std::make_shared<MyClass>(param)(或反过来)语法A需要更多重写的地方是微不足道的.

  • @reggaeguitar如果我看到一个"新",我需要停下来想一想:这个指针要活多长时间?我处理得当吗?如果有异常,是否一切都正确清理了?我不想问自己这些问题,浪费我的时间,如果我不使用"新",我不必问这些问题. (37认同)
  • 想象一下,你对项目的所有源文件进行了grep,并且找不到一个`new`.这不是很好吗? (4认同)
  • “不要使用新的”准则的主要优点是它很简单,因此它是向您经验不足的开发人员提供容易的准则。我一开始并没有意识到,但这本身就是有价值的 (4认同)
  • @NathanOliver,你实际上_绝对_不必使用 `std::make_shared` - 想象一下分配的对象很大并且有很多 `std::weak_ptr`-s 指向它的情况:这会更好一旦最后一个共享指针被销毁,就让对象被删除,并只保留一个小的共享区域。 (3认同)
  • @NathanOliver,你不会。我所说的是 `std::make_shared` 的缺点 /sf/answers/1462699381/ 其中用于存储对象的内存直到最后一个 `std: 才能被释放: :weak_ptr` 消失了(即使所有指向它的 `std::shared_ptr` -s(以及对象本身)已经被销毁)。 (2认同)

Cal*_*eth 45

make_unique区分TT[]T[N],unique_ptr(new ...)没有.

您可以轻松地通过传递这是一个指针得到了一个未定义的行为new[]编的unique_ptr<T>,或传递,这是一个指针new编的unique_ptr<T[]>.


S.M*_*.M. 20

原因是更短的代码没有重复.相比

f(std::unique_ptr<MyClass>(new MyClass(param)), g());
f(std::make_unique<MyClass>(param), g());
Run Code Online (Sandbox Code Playgroud)

你保存MyClass,new并支持.与ptr相比,make中只需要一个字符.

  • 在其他答案的评论中已经说过,但是虽然c ++ 17为构造函数引入了模板类型推导,但在`std :: unique_ptr`的情况下,它是不允许的.它与区分`std :: unique_ptr <T>`和`std :: unique_ptr <T []>有关. (8认同)
  • 好吧,正如我在问题中所说的那样,只有一次提到"MyClass",我就可以看到它的输入较少,但我想知道是否有更强的理由使用它 (2认同)
  • 在许多情况下,演绎指南将有助于消除第一个变体中的"<MyClass>"部分. (2认同)

Yak*_*ont 18

每次使用new都必须经过仔细审核才能终身正确; 它会被删除吗?只有一次?

每次使用make_unique都不适合那些额外的特征; 只要拥有对象具有"正确"的生命周期,它就会递归地使唯一指针具有"正确".

现在,确实unique_ptr<Foo>(new Foo())在所有方面都是相同的1make_unique<Foo>(); 它只需要一个更简单的"grep你的源代码,new用于审计它们的所有用途".


1实际上是一般情况下的谎言.完美转发并不完美,{}默认的init,数组都是例外.

  • @Deduplicator而c ++ 17引入了构造函数的模板类型推导,在`std :: unique_ptr`的情况下它是不允许的.如果要区分`std :: unique_ptr <T>`和`std :: unique_ptr <T []>` (2认同)