Home > OS >  Using unique_ptr with an interface requiring pointer-pointer, to an abstract class
Using unique_ptr with an interface requiring pointer-pointer, to an abstract class

Time:09-28

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?

CodePudding user response:

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.

  •  Tags:  
  • c
  • Related