Reputation: 11012
RAII works great when allocating from global ressource / OS. Almost all the cases in the standard library uses some type of global resource, but suppose this is not the case. (An exception is of course custom allocators for containers, but this is not a very good example in my view of code you want in production (basicly just uses pointers everywhere)).
// obj_rep could for example contain an id number or handle/pointer of some kind, does not //matter so much
struct Manager() {
obj_rep allocate();
void deallocate(obj_rep);
}
struct MyObject {
MyObject (Manager& m) : mng {m} {
//call allocate with a manager object
rep = mng.allocate();
}
~MyObject () {
//call deallocate with the same manager object
mng.deallocate(rep);
}
//TODO: implement rule of 3/5 here
private:
obj_rep rep;
Manager& mng;
}
In the above example (and my current implementation) I stored a reference (could also be pointer) to a Manager
- this then requires the user to manage lifetime correctly. But is there a better way ? I know shared_ptr
/ weak_ptr
could be used, but is there a way to reverse the design somehow to get rid of lifetime issue and still have the RAII encapsulation ?
Smart/weak pointers and raw pointers should, for the most part, be avoided in library level code at the interface level (in c++).
Upvotes: 1
Views: 159
Reputation: 2438
First of all, using a reference for a class member is strongly discouraged by the C++ core guidelines ("Note that using a reference member is almost always wrong").
If all the objects are scoped objects, which is usually best practice (C++ core guideline R.5), the manager
has to be created on the outer scope or first at the same scope of the MyObject
objects. You can enforce being scoped objects poisoning the operator new.
If the MyObject
objects can be dynamically allocated, you can use shared_pointer
or any similar technique. Or you can enforce ownership of MyObject
objects by the Manager
(or a third object that owns both), and the latter will be in charge of creating and destroying MyObject
objects using RAII.
Upvotes: 1
Reputation: 29009
You mentioned in the title that the Manager
in not global.
Therefore I assume that somewhere you have a variable/member like Manager theManager
.
In order keep the RAII behavior of MyObject
and at the same time ensure automatic lifetime management of the Manager
instance, you can use std::shared_ptr
in the following way:
Manager
mentioned above should become a std::shared_ptr<Manager> theManager
.mng
member of MyObject
should become a std::shared_ptr<Manager> mng
(and the parameter of the MyObject
constructor should change accordingly).MyObject
instance pass the theManager
object (and the destructor will use mng
in an RAII style).The lifetime of the Manager
will be automatically managed by the std::shared_ptr
- it will be destroyed when theManager
is destroyed and it is no longer referenced by any MyObject
.
Upvotes: 2