Consider this simple class:
struct C {
C(const char* name) : name(name) {
cout << "constructing " << name << endl;
}
~C() {
cout << "destructing " << name << endl;
}
string name;
};
I would like to have a pointer to an instance to this class, which is routinely replaced with another instance. However, I would like for the current instance to be destructed before the new instance is created.
If I use a unique_ptr
in a normal fashion, this does not work:
unique_ptr<C> c( new C("the first one"));
c.reset(new C("the second one"));
(Undesired) Output:
constructing the first one
constructing the second one
destructing the first one
destructing the second one
The desired effect can be achieved as follows:
unique_ptr<C> c( new C("the first one"));
c.reset(); // explicitly destruct the first one first
c.reset(new C("the second one"));
Output:
constructing the first one
destructing the first one
constructing the second one
destructing the second one
This is my attempt at creating a smart pointer with this behavior. Does such a smart pointer exist already?
template<typename Resource>
class ResourceManager {
public:
ResourceManager() {}
template<typename... Arguments>
ResourceManager(Arguments&&... args) {
replace<Arguments...>(std::forward<Arguments>(args)...);
}
template<typename... Arguments>
void replace(Arguments&&... args) {
resource.reset();
resource.reset(new Resource(std::forward<Arguments>(args)...));
}
private:
unique_ptr<Resource> resource;
};
template<typename Resource, typename... Arguments>
ResourceManager<Resource> make_resource_manager(Arguments... args) {
return ResourceManager<Resource>(args...);
}
int main() {
//ResourceManager<C, const char*> r("first1");
auto r = make_resource_manager<C>("first1");
r.replace("second1");
}
Output:
constructing the first one
destructing the first one
constructing the second one
destructing the second one
EDIT: Moved 'Arguments...' template to the function level.
EDIT 2: Now forwarding 'Arguments' correctly.
Destroying the old state before constructing the new state is avoided in C++ as much as possible, because one cannot provide the strong exception guarantee that way: "The operation succeeds, or it throws an exception without changing anything". Thus, the standard library does not have such (I cannot even name a framework adding it).
Naive and wrong copy-constructors sometimes do it though.
If you deliberately want to get that behavior, there's nothing better than coding it for yourself.
But, be really sure that's what you want, and document it for posterity.
Your ResourceManager
seems mostly to do what you want.
Still, make really sure the method name/class name explicitly calls out your non-standard behavior (neither ResourceManager
nor replace
are specific enough).