Home > database >  unique_ptr is copying when raw pointer is passed into its constructor
unique_ptr is copying when raw pointer is passed into its constructor

Time:11-17

I am trying to understand how unique pointers work in modern C .

When I went through the documentations (cppreference and others), I was able to understand that unique_ptr will transfer ownership and not share it. But I am not able to understand why unique_ptr is acting strange when working with a raw pointer passed into its constructor.

For example:

#include <iostream>
#include <memory>

class foo{
    int x;
public:
    foo(): x(0) {}
    foo(int a): x(a) {}
    foo(const foo& f): x(f.x) {}
};

int main(){
    foo *ptr = new foo(5);
    std::unique_ptr<foo> uptr(ptr);
    std::cout << ptr << "\n";
    std::cout << uptr.get() << "\n";
    return 0;
}

Output below:

0x5c7bc80
0x5c7bc80

Queries:

  • Is the raw pointer being passed into the copy constructor? Isn't the copy constructor deleted (=delete)? Why is the raw pointer printing the same address as unique_ptr?
  • Is this a design flaw of unique_ptr?
  • How do I overcome this issue?
  • What is the use of std::make_unique()? I tried changing the line std::unique_ptr<foo> uptr(ptr); to std::unique_ptr<foo> uptr(std::make_unique<foo>(*ptr)); but nothing changed.

CodePudding user response:

Is the raw pointer being passed into the copy constructor?

Not the copy constructor, no (that takes another unique_ptr as input). The raw pointer is being passed to a converting constructor instead, specifically this one in this case:

explicit unique_ptr( pointer p ) noexcept;

Isn't the copy constructor deleted (=delete)?

Yes. But this code is not invoking the copy constructor.

Why is the raw pointer printing the same address as the unique_ptr?

Because the unique_ptr is simply copying the input pointer as-is into its own internal member pointer, taking ownership of the object that is being pointed at. You are printing the value of the two pointers, and they have the same value because they are pointing at the same object in memory.

Is this a design flaw of unique_ptr?

No.

How do I overcome this issue?

What issue? There is no issue here. The unique_ptr is acting as designed.

What is the use of std::make_unique()?

To more efficiently allocate memory, construct an object in that memory, and take ownership of that memory with a new unique_ptr, all in one operation.

I tried changing the line std::unique_ptr<foo> uptr(ptr); to std::unique_ptr<foo> uptr(std::make_unique<foo>(*ptr)); but nothing changed.

It should have.

The expression std::make_unique<foo>(*ptr) is creating a new foo object that is separate from the object that ptr is pointing at. It will pass the dereferenced *ptr object to the new foo object's copy constructor.

And then, in the expression std::unique_ptr<foo> uptr(...);, uptr is moving the unique_ptr that make_unique() returns, which is pointing at the new foo object. So uptr now owns that foo object.

Subsequently, your 2 prints should be outputting different values, since ptr and uptr are pointing at different foo objects.

Note that in this situation, you would be leaking the foo object that ptr is pointing at, since no unique_ptr is taking ownership of that object. So you are responsible for delete'ing it manually.

This code:

foo *ptr = new foo(5);
std::unique_ptr<foo> uptr(ptr);

Can be changed to this instead:

std::unique_ptr<foo> uptr = std::make_unique<foo>(5);

or:

auto uptr = std::make_unique<foo>(5);

std::make_unique() allocates and constructs the type specified in its template argument, passing the input parameters to that object's constructor.

  • Related