如何将 std::unique_ptr 传递给函数

How can I pass std::unique_ptr into a function

如何将 std::unique_ptr 传递给函数?假设我有以下 class:

class A
{
public:
    A(int val)
    {
        _val = val;
    }

    int GetVal() { return _val; }
private:
    int _val;
};

以下不编译:

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);

    return 0;
}

为什么我不能将 std::unique_ptr 传递给函数?这肯定是构造的主要目的吗?或者 C++ 委员会是否打算让我退回到原始 C 风格的指针并像这样传递它:

MyFunc(&(*ptr)); 

最奇怪的是,为什么这是一种正确的传递方式?这似乎非常不一致:

MyFunc(unique_ptr<A>(new A(1234)));

这里基本上有两个选项:

通过引用传递智能指针

void MyFunc(unique_ptr<A> & arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(ptr);
}

将智能指针移动到函数参数中

请注意,在这种情况下,断言将成立!

void MyFunc(unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

int main(int argc, char* argv[])
{
    unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
    MyFunc(move(ptr));
    assert(ptr == nullptr)
}

因为 unique_ptr 是唯一所有权,如果你想把它作为参数传递,试试

MyFunc(move(ptr));

但之后 ptrmain 中的状态将是 nullptr.

您正在按值传递它,这意味着制作副本。那不会很独特吧?

您可以移动该值,但这意味着将对象的所有权和其生命周期的控制权传递给函数。

如果保证对象的生命周期存在于调用 MyFunc 的生命周期内,只需通过 ptr.get() 传递一个原始指针。

Why can I not pass a unique_ptr into a function?

你可以,但不能复制 - 因为 std::unique_ptr<> 不可复制构造。

Surely this is the primary purpose of the construct?

除其他外,std::unique_ptr<> 旨在明确标记 唯一 所有权(与 std::shared_ptr<> 相对)。

And most strangely of all, why is this an OK way of passing it?

因为在那种情况下,没有复制构造。

Why can I not pass a unique_ptr into a function?

你不能那样做,因为 unique_ptr 有移动构造函数但没有复制构造函数。按照标准,当定义了移动构造函数而没有定义拷贝构造函数时,拷贝构造函数被删除

12.8 Copying and moving class objects

...

7 If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted;

您可以使用以下方法将 unique_ptr 传递给函数:

void MyFunc(std::unique_ptr<A>& arg)
{
    cout << arg->GetVal() << endl;
}

并像您一样使用它:

void MyFunc(std::unique_ptr<A> arg)
{
    cout << arg->GetVal() << endl;
}

并像这样使用它:

std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234));
MyFunc(std::move(ptr));

重要提示

请注意,如果您使用第二种方法,ptr在调用std::move(ptr)后没有指针的所有权returns。

void MyFunc(std::unique_ptr<A>&& arg)void MyFunc(std::unique_ptr<A>& arg) 具有相同的效果,因为两者都是引用。

在第一种情况下,ptr在调用MyFunc后仍然拥有指针的所有权。

由于MyFunc没有所有权,最好有:

void MyFunc(const A* arg)
{
    assert(arg != nullptr); // or throw ?
    cout << arg->GetVal() << endl;
}

或更好

void MyFunc(const A& arg)
{
    cout << arg.GetVal() << endl;
}

如果你真的想获得所有权,你必须移动你的资源:

std::unique_ptr<A> ptr = std::make_unique<A>(1234);
MyFunc(std::move(ptr));

或者直接传递一个右值引用:

MyFunc(std::make_unique<A>(1234));

std::unique_ptr 故意没有副本以保证只有一个所有者。

std::unique_ptr<T> 作为值传递给函数是行不通的,因为正如你们所说,unique_ptr 不可复制。

这个呢?

std::unique_ptr<T> getSomething()
{
   auto ptr = std::make_unique<T>();
   return ptr;
}

此代码有效