1

I'm using RocksDB which requires a pointer to a pointer to open:

rocksdb::DB* db{nullptr};
const rocksdb::Status status = rocksdb::DB::Open(options, path, &db);

As expected, I'd like to use a unique_ptr. However, unfortunately if I do this:

std::unique_ptr<rocksdb::DB> db;
const rocksdb::Status status = rocksdb::DB::Open(options, fileFullPath, &(db.get()));

I get:

error: lvalue required as unary ‘&’ operand

and if I use a raw pointer and then create a unique_ptr:

std::unique_ptr<rocksdb::DB> _db; // Class member
rocksdb::DB* db;
const rocksdb::Status status = rocksdb::DB::Open(options, fileFullPath, &db));
_db = std::make_unique<rocksdb::DB>(db);

I get:

 error: invalid new-expression of abstract class type ‘rocksdb::DB’
 { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }

How can I use unique_ptr with this?

user997112
  • 29,025
  • 43
  • 182
  • 361
  • 2
    Shouldn't that be `_db.reset(db);`? – UnholySheep Sep 27 '21 at 16:31
  • I thought `reset()` is only if it currently holds a valid value, otherwise it's `make_unique` – user997112 Sep 27 '21 at 16:34
  • 1
    `&(db.get())` translates to get the address represented by the `unique_ptr` and then take the address of the address. Not what you want. The error message you get is because the address returned is in a temporary variable and you can't take the address of a temporary. They just aren't around long enough for it to be useful. – user4581301 Sep 27 '21 at 16:36
  • `db.get()` returns a temporary. What about doing `auto ptr = db.get()` and then `const rocksdb::Status status = rocksdb::DB::Open(options, fileFullPath, &ptr);` ? – Dundo Sep 27 '21 at 16:36
  • When someone wants a pointer to a pointer, it's typically because they're going to update the pointer you provide with a new address. Get the address from `Open` and then put it in the `unique_ptr` **if it is safe to do so**. Who is responsible for freeing the pointer? Are you absolutely sure it is you? What are the rules for releasing the pointer? Use `delete`? Call `free`? Call a close function? – user4581301 Sep 27 '21 at 16:39
  • Related to [understanding-stdinout-ptr-and-stdout-ptr-in-c23](https://stackoverflow.com/questions/68918312/understanding-stdinout-ptr-and-stdout-ptr-in-c23). – Jarod42 Sep 27 '21 at 16:41
  • 1
    @user4581301 This page implicitly implies I can delete the pointer when I wish: http://rocksdb.org/docs/getting-started.html – user997112 Sep 27 '21 at 16:44
  • 1
    Good. Eliminates one potential source of problems. – user4581301 Sep 27 '21 at 16:45
  • @user997112 "Why is `reset` different to `make_unique`??" - see the answer I just posted. – Remy Lebeau Sep 27 '21 at 18:57

1 Answers1

2

Using a raw pointer to accept the value from Open() is the correct solution, since that is what the function is expecting.

However, the way you are creating the unique_ptr afterwards is not correct.

Use this instead:

std::unique_ptr<rocksdb::DB> _db; // Class member
...
rocksdb::DB* db;
const rocksdb::Status status = rocksdb::DB::Open(options, fileFullPath, &db);
_db = std::unique_ptr<rocksdb::DB>(db);

Online Demo

Alternatively:

std::unique_ptr<rocksdb::DB> _db; // Class member
...
rocksdb::DB* db;
const rocksdb::Status status = rocksdb::DB::Open(options, fileFullPath, &db);
_db.reset(db);

Online Demo

std::make_unique() creates a new object of the specified type, and then wraps the raw pointer inside of a new std::unique_ptr.

On the other hand, unique_ptr::operator= and unique_ptr::reset() merely update an existing std::unique_ptr with a new raw pointer (destroying the object pointed by the old raw pointer that is being replaced).

Since rocksdb::DB is an abstract type, you can't directly create instances of it, which is why your std::make_unique() calls fails to compile. But even if you could create DB objects directly, std::make_unique<rocksdb::DB>(db) would be passing db as a parameter to the rocksdb::DB constructor, which is not what you want in this situation anyway. You just want the _db smart pointer to take ownership of the db raw pointer.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770