2

例如,我有一堂课

class A
{
public:
    // argument with default value is too long, any better way
    A(std::unique_ptr<int> data = std::unique_ptr<int>(new int(10))) 
        : mData(std::move(data))
    {}

    // Is r-value better? Is the following code okay?
    A(std::unique_ptr<int>&& data = std::unique_ptr<int>(new int(10)))
        : mData(data)
    {}

private:
    std::unique_ptr<int> mData;
};
4

1 回答 1

4

乍一看,您似乎可以这样做:

A (std::unique_ptr<int> data = {new int(10)}) 
    : mData(std::move(data))
{}

请注意花括号的使用(即统一初始化)。但是,这不起作用(无法编译),因为unique_ptr接受指针的构造函数被声明为explicit,这在此处排除了它的使用。

你可以做的另一件事是:

A (int * data = new int(10)) 
    : mData (data)
{}

也就是说,接受一个普通的指针并从中构造你的成员。而且你也不需要离开它(std::move尽管仍然推荐。)

这个确实可以编译并且可以工作,但是它有一个致命的缺陷,即尽管您正在接管传入指针的所有权(您将要访问delete它),但您并没有在界面中显示此行为。因此,这个新界面将比以前的界面提供更少的信息。

另一种方法是编写一个快捷函数模板,如下所示:

template <typename T>
std::unique_ptr<T> uptr (T * v)
{
    return std::unique_ptr<T>(v);
}

然后,您的构造函数变为:

A(std::unique_ptr<int> data = uptr(new int(10))) 
    : mData(std::move(data))
{}

但在我看来,这并没有太大的进步。

但是,如果这个特定用例是您的全部问题,为什么不直接定义一个默认构造函数和一个单参数构造函数,如下所示:

A () 
    : mData (new int (10))
{}

/*explicit*/ A (std::unique_ptr<int> data)
    : mData(std::move(data))
{}

这只是更明智。(请注意,提出explicit一个好主意和好形式,但与您的问题无关,因此我已将其注释掉。)

此外,您的第二个构造函数实际上并没有移动任何东西。在这种情况下,r 值引用类型不像您认为的那样工作。简而言之,既然data有了名字,它就不再是一个右值,尽管它的类型仍然是对某物的右值引用。

于 2013-07-27T21:50:42.490 回答