[odb-users] Strange behavior of odb::details::transfer_ptr
Reilly He
reillyhekazusa at gmail.com
Wed Apr 26 23:02:00 EDT 2023
Dear Boris,
Sorry to bother you again, I wrote this to you just to make sure *the usage
of transfer_ptr*.
1.Env
The general environment is:
- *Compiler*: CXX11
- *OS*: Android&IOS
- *Inner DB*: SQLite
2. Background information
Below is the code in our project for database opening. As you can see, we
use our own implementation of connection-pool.
> //create database under wal
>
> //create connection pool for database
>
> auto connectionPoolDelegate = std::make_shared<
> StandardDelegate>();
>
> //the pool will be access ONLY by ODB database after creation
>
> std::unique_ptr<odb::sqlite::connection_factory> rwPool(new
> RWConnectionPool(connectionPoolDelegate, config));
>
> //the transfer pointer is a WEIRD pointer used by ODB
>
> odb::details::transfer_ptr<odb::sqlite::connection_factory>
> poolInTransP = odb::details::transfer_ptr<odb::sqlite::connection_factory
> >(std::move(rwPool));
>
> auto db = std::shared_ptr<odb::sqlite::database>(new odb::
> sqlite::database(dbFile,
>
>
> SQLITE_OPEN_READWRITE
>
>
> | SQLITE_OPEN_CREATE
>
>
> | SQLITE_OPEN_FULLMUTEX
>
>
> | SQLITE_OPEN_PRIVATECACHE,
>
>
> false,
>
>
> "",
>
>
> poolInTransP));
>
> //the tricky part is you have to release the transfer pointer
> in here
>
> //otherwise it will cause double release for this connection
> pool
>
> poolInTransP.transfer();
>
> return db;
>
I was really confused about transfer_ptr, I reckon this is *very buggy*
because you have to t*ransfer() the ptr everytime* in its scope.
Then reason why I have to do this is after checking the s*ource code
of transfer_ptr*, I realized that it will d*eallocate the inner ptr it was
holding in transfer_ptr`s deallocator*:
> ~transfer_ptr () {delete p_;}
>
>
> T*
>
> transfer ()
>
> {
>
> T* r (p_);
>
> p_ = 0;
>
> return r;
>
> }
>
And in the constructor of odb::sqlite::database, *it takes a transfer_ptr
via its copy constructor:*
> database::
> database (const string& name,
> int flags,
> bool foreign_keys,
> const string& vfs,
> transfer_ptr<connection_factory> factory)
> : odb::database (id_sqlite),
> name_ (name),
> flags_ (flags),
> foreign_keys_ (foreign_keys),
> vfs_ (vfs),
> factory_ (factory.transfer ())
> {
> if (!factory_)
> factory_.reset (new connection_pool_factory ());
>
> factory_->database (*this);
> }
>
> Thus, during this scope, *2 transfer_ptrs existed in memory,* and as a
result, when we leave the current scope. The *real ptr will be deallocated
by the first transfer_ptr* if we do not transfer it explicitly.
3. Question
Is it *better* to take an *r-value* of transfer_ptr in the constructor of
odb::sqlite::database? And I reckon it is even better to just *delete
transfer_ptr`s copy constructor*.
Since odb supports C++ 11, why just allow us to move our connection pool
into the factory_ member via *std::unique_ptr*?
Thanks a lot for the help, really appreciated.
Best Regards,
Reilly He
More information about the odb-users
mailing list