为什么 C++ 需要 std::make_unique over forwarded unique_ptr 构造函数?
Why does C++ need std::make_unique over forwarded unique_ptr constructor?
我不像here一样询问new operator
。请仔细阅读问题。
我想知道为什么我们需要特殊的函数 make_unique
而不是特殊的构造函数
unique_ptr.
unique_ptr
可以使用这样的构造函数来使 make_unique
变得不必要:
template<typename T, typename ...TArgs>
unique_ptr::unique_ptr(TArgs&&... args)
: inner_ptr(new T(std::forward(args)...))
{}
这有几个原因。
第一个与一些 C++ 历史有关。在 C++17 之前,构造函数没有异常安全,因此执行以下操作:
some_func(std::unique_ptr<T1>(), std::unique_ptr<T2>())
如果 T1 的构造函数抛出异常, 会泄漏内存,因为 C++ 标准没有要求,在这种情况下,第一个 unique_ptr 应该释放内存。自 C++17
以来不再是这种情况
其次,它允许更通用的规则“永远不要使用 new
”,没有 make_unique
将是“永远不要使用 new
,除非使用 unique_ptr
或 shared_ptr
"
还有一个额外的好处是没有多余的输入,就像你必须做的构造函数一样:
auto p = std::unique_ptr<T>(new T());
列出 T
两次,这在长类型名称的情况下尤其难看。使用 make_unique
这缩短为
auto p = std::make_unique<T>();
我想总结与Some programmer dude, StoryTeller - Unslander Monica and Raymond Chen
的讨论
所以,有两个原因:
std::make_unique
与之前介绍的 std::make_shared 配对良好,因此这比 unique_ptr
. 的新构造函数更容易学习
unique_ptr
的构造函数和内部值类型 (T
) 的构造函数之间可能存在歧义,如果此类型有自己的构造函数,该构造函数采用指向自身类型的指针。例如
struct Inner{
Inner() = default;
Inner(Inner* parent_node): parent(parent_node){}
Inner* parent = nullptr;
};
Inner* parent = make_parent();
// It would be not clear for human which constructor must be called here
std::unique_ptr<Inner> child(parent);
编译器可以推断出应该在此处调用哪个构造函数,但这对人类来说很难。所以拥有函数 std::make_unique
是有益的,因为很明显 std::unique_ptr
的所有构造函数只创建 unique_ptr 并且从不调用内部值构造函数,而 std::make_unique
总是调用内部值的构造函数。这使得代码更容易推理。
感谢大家的讨论!
我不像here一样询问new operator
。请仔细阅读问题。
我想知道为什么我们需要特殊的函数 make_unique
而不是特殊的构造函数
unique_ptr.
unique_ptr
可以使用这样的构造函数来使 make_unique
变得不必要:
template<typename T, typename ...TArgs>
unique_ptr::unique_ptr(TArgs&&... args)
: inner_ptr(new T(std::forward(args)...))
{}
这有几个原因。
第一个与一些 C++ 历史有关。在 C++17 之前,构造函数没有异常安全,因此执行以下操作:
some_func(std::unique_ptr<T1>(), std::unique_ptr<T2>())
如果 T1 的构造函数抛出异常,会泄漏内存,因为 C++ 标准没有要求,在这种情况下,第一个 unique_ptr 应该释放内存。自 C++17
以来不再是这种情况其次,它允许更通用的规则“永远不要使用 new
”,没有 make_unique
将是“永远不要使用 new
,除非使用 unique_ptr
或 shared_ptr
"
还有一个额外的好处是没有多余的输入,就像你必须做的构造函数一样:
auto p = std::unique_ptr<T>(new T());
列出 T
两次,这在长类型名称的情况下尤其难看。使用 make_unique
这缩短为
auto p = std::make_unique<T>();
我想总结与Some programmer dude, StoryTeller - Unslander Monica and Raymond Chen
的讨论所以,有两个原因:
std::make_unique
与之前介绍的 std::make_shared 配对良好,因此这比unique_ptr
. 的新构造函数更容易学习
unique_ptr
的构造函数和内部值类型 (T
) 的构造函数之间可能存在歧义,如果此类型有自己的构造函数,该构造函数采用指向自身类型的指针。例如
struct Inner{
Inner() = default;
Inner(Inner* parent_node): parent(parent_node){}
Inner* parent = nullptr;
};
Inner* parent = make_parent();
// It would be not clear for human which constructor must be called here
std::unique_ptr<Inner> child(parent);
编译器可以推断出应该在此处调用哪个构造函数,但这对人类来说很难。所以拥有函数 std::make_unique
是有益的,因为很明显 std::unique_ptr
的所有构造函数只创建 unique_ptr 并且从不调用内部值构造函数,而 std::make_unique
总是调用内部值的构造函数。这使得代码更容易推理。
感谢大家的讨论!