用括号初始化的make_unique

MvG*_*MvG 10 c++ initialization unique-ptr c++-standard-library c++14

https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique写入std::make_unique可以实现为

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
Run Code Online (Sandbox Code Playgroud)

这对于没有构造函数的普通结构不起作用。可以将它们初始化,但没有非默认构造函数。例:

#include <memory>
struct point { int x, z; };
int main() { std::make_unique<point>(1, 2); }
Run Code Online (Sandbox Code Playgroud)

编译它会使编译器抱怨缺少2参数的构造函数,这是正确的。

我想知道,是否有任何技术理由不根据大括号初始化来定义函数?如

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
Run Code Online (Sandbox Code Playgroud)

对于上面的方案,这已经足够好了。还有其他合法的用例会破坏吗?

看到总体趋势似乎倾向于使用括号进行初始化,我认为在该模板中制作括号是一种典型的选择,但是标准不这样做的事实可能表明我缺少某些东西。

son*_*yao 10

某些类的两种初始化样式具有不同的行为。例如

std::vector<int> v1(1, 2); // 1 element with value 2
std::vector<int> v2{1, 2}; // 2 elements with value 1 & 2
Run Code Online (Sandbox Code Playgroud)

可能没有足够的理由选择一个偏爱另一个。我认为该标准只是选择一项并明确陈述该决定。

解决方法是,您可能要实现自己的make_unique版本。正如您所展示的,这不是一项艰巨的工作。

  • 不,C++20 不会破坏答案的任何内容。两个版本的 std::vector 构造函数仍然不同,make_shared 仍然会调用圆括号构造函数(委员会永远不会支持破坏大量代码的更改)。但是,C++20 将允许使用标准大括号进行聚合初始化。 (3认同)

Bar*_*rry 8

在C ++ 20中,它将编译为:

std::make_unique<point>(1, 2);
Run Code Online (Sandbox Code Playgroud)

由于新规则允许从带括号的值列表中初始化聚合


在C ++ 17中,您可以执行以下操作:

std::unique_ptr<point>(new point{1, 2});
Run Code Online (Sandbox Code Playgroud)

那将不起作用make_shared。因此,您也可以只创建一个工厂(作为练习左转):

template <typename... Args>
struct braced_init {
    braced_init(Args... args) : args(args...) { }
    std::tuple<Args...> args;

    template <typename T>
    operator T() const {
        return std::apply([](Args... args){
            return T{args...};
        }, args);
    }
};

std::make_unique<point>(braced_init(1, 2));
Run Code Online (Sandbox Code Playgroud)

在C ++ 14中,您必须实现apply并编写一个工厂函数,braced_init因为还没有CTAD-但这是可行的。


了解总体趋势如何倾向于使用括号进行初始化

需要引用。这是一个收费的话题-但我绝对不同意这一说法。

  • 对于 C++20,这仍然无法编译: `auto p = std::make_unique&lt;std::array&lt;int, 2&gt;&gt;(1, 2);` C++ 初始化是一个包裹在谜团中的谜语。 (2认同)

Evg*_*Evg 7

除了其他答案之外,在他关于 C++17 的演讲中Alisdair Meredith给出了以下实现make_unique

template<typename T, typename... Args>
auto make_unique(Args&&... args) -> std::unique_ptr<T> {
    if constexpr (std::is_constructible<T, Args...>::value)
        return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
    else
        return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
Run Code Online (Sandbox Code Playgroud)

它使用 C+17 if constexpr,但没有它可以很容易地重写。

使用此版本,您可以同时进行

auto v = make_unique<std::vector<int>>(10, 20); // *v is a vector of 10 elements
Run Code Online (Sandbox Code Playgroud)

auto p = make_unique<point>(10, 20); // *p is a point (10, 20)
Run Code Online (Sandbox Code Playgroud)