Copying an RAII object entails copying the resource it manages, so the copying behavior of the resource determines the copying behavior of the RAII object.
We can use
tr1::shared_ptr to manage heap-based resources, as introduced in item 13. However, not all resources are heap-based, and for such resources, we need to create our own resource-managing classes to deal with a general question:
what should happen when an RAII object is copied?
Mostly, there are 4 possibal choices:
1. Prohibit copying
In some cases, it makes no sense to allow RAII objects to be copied, so we should prohibit it. As explained in item 6, we declare the copying operations
private without definition. A good example is class
Mutex, which is synchronization primitives and comes with two functions
We should not forget to unlock a
Mutex we’ve locked, and it rarely makes sense to have “copies” of synchronization privitives, so we can create an uncopyable class to manage the locks:
And we can use
Lock in the conventional RAII fashion:
2. Reference-count the underlying resource
Sometimes it’s desirable to hold on to a resource until the last object using it has been destroyed. We could implement reference-counting copying behavior by containing a
tr1::shared_ptr data member, but in some cases we may have to customize the behavior when the reference count goes to zero, for the default behavior is to call
The way we customize
tr1::shared_ptr is to specify a “deleter” - a function or function object to be called when the reference count goes to zero (
auto_ptr does not give us this privilege), which is an optional second parameter to the
Since a class’s destructor (both user-defined ones and compilter-generated ones) automatically invokes the destructors of the class’s non-static data members, there’s no need to declare a destructor for class
Lock explicitly (item 5). We simply rely on the default compilter-generated behavior, and that’s enough.
3. Copy the underlying resource
Sometimes we want to copy the resource-managing object as well as the resource it wraps, - that is to say, we want the resourse-managing object to perform a “deep copy”. A good example is the standard
string type: in sompe implementation, a
string type object consists of a pointer to heap memory, where the charactors making up the string are stored, and a copy is made of both the pointer and the memory it points to when such an object get copied.
4. Transfer owenership of the underlying resource
On rere occasions, we wish only one RAII object refers to a raw resource and the ownership of the resource is transfered from the copied object to the copying object, as is the meaning of “copy” used by
In this situation, we may have to write our own version of copying functions (copy constructor and copy assignment operator), since the default compiler-generated ones may not do what we want. In some cases, we’ll also want to support generalized versions of copying functions, which is discussed in item 45.