Home > Blockchain >  How do I create a unique_ptr from a raw pointer, by reference?
How do I create a unique_ptr from a raw pointer, by reference?

Time:01-29

I'm calling a library function which returns a raw pointer to a class object, but I'd like to wrap the returned pointer in a unique_ptr. I don't know how the library creates the pointer, but I'm assuming that it uses new (see the comment in the code below).

Is the code below a valid way to create the unique_ptr and return it by reference from a function call? The code does print '42', but is there a better way to do this?


The library is the MariaDB C connector. Unfortunately, it has minimal documentation. I asked about this on SO a couple of days ago, but had no response so far. I'd use the MySQL version instead, but it doesn't seem to be much better. However, there is an example program, which includes this line in main:

std::unique_ptr<sql::Connection> conn(driver->connect(url, properties));

So, having read the comments and the answer, I think I can now assume that the Connection object that I want was newed. On the other point, of why I'm passing by reference instead of just returning the unique_ptr - good question. The only reason is that all the other code in this app returns a bool as a success status, so I thought it would be more consistent to do the same here.

Original code:

#include <memory>
#include <iostream>

class A {
public:
   int b;
   A() : b(42) {}
};

void create(std::unique_ptr<A> &p) {
   A *a = new A; // this is actually a function call which returns an A*
   p.reset(a);
}

int main() {
   std::unique_ptr<A> foo;
   create(foo);
   std::cout << "foo.b is " << foo->b << '\n';
}

CodePudding user response:

What you wrote works if and only if the pointer is created with new. But even then, just delete'ing it may not be enough to uninitialize it properly, hence why you should always stick to managing this pointer in accordance with the library's documentation.

However, smart pointers are designed to account for cases like this, by allowing you to use a custom deleter function.

So, the proper way would be something like this:

using my_ptr_t = std::unique_ptr<A, void(*)(A*)>;

void create(my_ptr_t& out) {
    A* a = ... // get the pointer
    out = my_ptr_t(a, [](A* p) -> void {
        // Uninitialize the pointer as dictated
        // by the library's documentation
        ...
    });
};
  • Related