繁体   English   中英

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

[英]Why use std::make_unique in C++17?

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

f(std::unique_ptr<MyClass>(new MyClass(param)), g()); // Syntax A

(解释:如果评估先为原始指针分配内存,然后调用g()并在std::unique_ptr构造之前抛出异常,则内存泄漏。)

调用std::make_unique是一种限制调用顺序的方法,从而使事情变得安全:

f(std::make_unique<MyClass>(param), g());             // Syntax B

从那时起,C++17 明确了求值顺序,使 Syntax A 也变得安全,所以这是我的问题:在 C++17 中,是否还有理由使用std::make_unique而不是std::unique_ptr的构造函数? 你能举一些例子吗?

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

需要明确的是,我并不是在提倡从标准库中删除std::make_unique (保持它至少对于向后兼容是有意义的),而是想知道是否仍然存在强烈偏好它的情况std::unique_ptr

你是对的,主要原因已被删除。 仍然有不使用新的准则,并且它是较少输入的原因(不必重复输入或使用单词new )。 诚然,这些都不是强有力的论据,但我真的不喜欢在我的代码中看到new的东西。

也不要忘记一致性。 你绝对应该使用make_shared所以使用make_unique是自然的并且符合模式。 然后将std::make_unique<MyClass>(param)更改为std::make_shared<MyClass>(param) (或相反)变得微不足道,其中语法 A 需要更多的重写。

make_uniqueTT[]T[N]区分开来, unique_ptr(new...)则不然。

通过将经过new[]编辑的指针传递给unique_ptr<T> ,或者将经过new编辑的指针传递给unique_ptr<T[]> ,您可以轻松获得未定义的行为。

原因是代码更短,没有重复。 比较

f(std::unique_ptr<MyClass>(new MyClass(param)), g());
f(std::make_unique<MyClass>(param), g());

您保存MyClassnew和大括号。 ptr相比, make只多花一个字符。

每次使用new都必须格外仔细地审核,以确保生命周期的正确性; 它会被删除吗? 只有一次?

每次使用make_unique都不是为了那些额外的特征; 只要拥有对象具有“正确”的生命周期,它就会递归地使唯一指针具有“正确”。

现在,确实unique_ptr<Foo>(new Foo())在所有方面都相同1make_unique<Foo>() 它只需要一个更简单的“grep 您的源代码,以便对new的所有用途进行审核”。


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

从那时起,C++17 明确了求值顺序,使 Syntax A 也变得安全

那真的不够好。 依靠最近引入的技术条款作为安全保证并不是一个非常稳健的做法:

  • 有人可能会在 C++14 中编译此代码。
  • 您会鼓励在别处使用原始的new ,例如通过复制粘贴您的示例。
  • 正如 SM 所建议的那样,由于存在代码重复,一种类型可能会被更改而另一种类型可能不会更改。
  • 某种自动 IDE 重构可能会把这个new东西移到别处(好吧,当然,这种可能性不大)。

通常,最好让您的代码适当/健壮/明确有效,而无需诉诸语言分层,在标准中查找次要或晦涩的技术条款。

(这基本上与我在这里提出的关于元组销毁顺序的论点相同。)

考虑 void function(std::unique_ptr(new A()), std::unique_ptr(new B())) {... }

假设 new A() 成功,但 new B() 抛出异常:您捕获它以恢复程序的正常执行。 不幸的是,C++ 标准不要求对象 A 被销毁并释放其内存:内存悄无声息地泄漏并且没有办法清理它。 通过将 A 和 B 包装到 std::make_uniques 中,您可以确定不会发生泄漏:

void function(std::make_unique(), std::make_unique()) {... } 这里的重点是 std::make_unique 和 std::make_unique 现在是临时对象,并且在中正确指定了临时对象的清理C++ 标准:它们的析构函数将被触发并释放内存。 所以如果可以的话,总是喜欢使用 std::make_unique 和 std::make_shared 分配对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM