Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass std::unique_ptr into a function

How can I pass a std::unique_ptr into a function? Lets say I have the following class:

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

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

The following does not compile:

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;
}

Why can I not pass a std::unique_ptr into a function? Surely this is the primary purpose of the construct? Or did the C++ committee intend for me to fall back to raw C-style pointers and pass it like this:

MyFunc(&(*ptr)); 

And most strangely of all, why is this an OK way of passing it? It seems horribly inconsistent:

MyFunc(unique_ptr<A>(new A(1234)));
like image 949
user3690202 Avatar asked Oct 03 '22 08:10

user3690202


People also ask

How do I pass a unique_ptr argument to a constructor or a function?

You cannot copy a unique_ptr . You can only move it. The proper way to do this is with the std::move standard library function. If you take a unique_ptr by value, you can move from it freely.

Can I move unique_ptr?

A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it. We recommend that you restrict an object to one owner, because multiple ownership adds complexity to the program logic.

What does the get () function of the unique_ptr class do?

std::unique_ptr::getReturns the stored pointer. The stored pointer points to the object managed by the unique_ptr, if any, or to nullptr if the unique_ptr is empty.


3 Answers

There's basically two options here:

Pass the smart pointer by reference

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);
}

Move the smart pointer into the function argument

Note that in this case, the assertion will hold!

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)
}
like image 210
Bill Lynch Avatar answered Oct 16 '22 14:10

Bill Lynch


You're passing it by value, which implies making a copy. That wouldn't be very unique, would it?

You could move the value, but that implies passing ownership of the object and control of its lifetime to the function.

If the lifetime of the object is guaranteed to exist over the lifetime of the call to MyFunc, just pass a raw pointer via ptr.get().

like image 47
Mark Tolonen Avatar answered Oct 16 '22 15:10

Mark Tolonen


Why can I not pass a unique_ptr into a function?

You cannot do that because unique_ptr has a move constructor but not a copy constructor. According to the standard, when a move constructor is defined but a copy constructor is not defined, the copy constructor is deleted.

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;

You can pass the unique_ptr to the function by using:

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

and use it like you have:

or

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

and use it like:

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

Important Note

Please note that if you use the second method, ptr does not have ownership of the pointer after the call to std::move(ptr) returns.

void MyFunc(std::unique_ptr<A>&& arg) would have the same effect as void MyFunc(std::unique_ptr<A>& arg) since both are references.

In the first case, ptr still has ownership of the pointer after the call to MyFunc.

like image 21
R Sahu Avatar answered Oct 16 '22 14:10

R Sahu