Copy on Write
Classes
RWCString,
RWWString, and
RWTValVirtualArray<T> use a technique called
copy on write to minimize copying. This technique offers the advantage of easy-to-understand value semantics with the speed of reference counted pointer implementation.
Here is how the technique works. When an
RWCString is initialized with another
RWCString via the copy constructor:
RWCString(const RWCString&);
the two strings share the same data until one of them tries to write to it. At that point, a copy of the data is made and the two strings go their separate ways. Copying only at “write” time makes copies of strings, particularly read-only copies, very inexpensive. In the following example, you can see how four objects share one copy of a string until one of the objects attempts to change the string:
#include <rw/cstring.h>
RWCString g; // Global object
void setGlobal(RWCString x) { g = x; }
int main(){
RWCString a("kernel"); // 1
RWCString b(a);
RWCString c(a); // 2
setGlobal(a); // Still only one copy of "kernel"! // 3
b += "s"; // Now b has its own data: "kernels" // 4
return 0;
}
A More Comprehensive Example
Because copies of
RWCStrings are so inexpensive, you are encouraged to store them by value inside your objects, rather than storing a pointer. This will greatly simplify their management, as the following comparison demonstrates. Suppose you have a window whose background and foreground colors can be set. A simple-minded approach to setting the colors would be to use pointers as follows:
class SimpleMinded {
const RWCString* foreground;
const RWCString* background;
public:
setForeground(const RWCString* c) {foreground=c;}
setBackground(const RWCString* c) {background=c;}
};
On the surface, this approach is appealing because only one copy of the string need be made. In this sense, calling setForeground() seems efficient. However, a closer look indicates that the resulting semantics can be muddled: what if the string pointed to by foreground changes? Should the foreground color change? If so, how will class Simple know of the change? There is also a maintenance -problem: before you can delete a color string, you must know if anything is still pointing to it.
Here is a much easier approach:
class Smart {
RWCString foreground;
RWCString background;
public:
setForeground(const RWCString& c) {foreground=c;}
setBackground(const RWCString& c) {background=c;}
Now the assignment foreground=c will use value semantics. The color that class Smart should use is completely unambiguous. Copy on write makes the process efficient, too, since a copy of the data will not be made unless the string should change. The next example maintains a single copy of white until white is changed:
Smart window;
RWCString color("white");
window.setForeground(color); // Two references to white
color = "Blue"; // One reference to white, one to blue