In the countless arguments about the superiority of C++-style deterministic destruction (RAII) versus garbage-collection, proponents of the former often suggest that it can do everything garbage-collection can do. There is, however, a pattern which is used frequently in Java and .NET languages, but for which I know no nice pattern in C++. Consider the class [could be Java or C#; using public fields for brevity}
public class MaxItemIdentifier
{
public String maxItemName = null;
public long maxItemValue = -0x7FFFFFFFFFFFFFFF-1;
public void checkItem(String name, long value)
{
if (value > maxItemValue)
{
maxItemName = name;
maxItemValue = value;
}
}
}
In both Java and C#, the above method may safely be passed a string that was created on any thread. Further, while the method is not thread-safe, even improper threading usage will not jeopardize memory safety; maxItemName
would still be guaranteed to either be null
or identify one of the strings passed to checkItem
. Additionally, the method never actually has to copy (or even look at) the contents of any string; all it acts upon are string references. Since no string object whose reference has been exposed to the outside world will ever be modified, a reference to a string may be considered synonymous with the sequence of characters identified thereby, and copying the reference is equivalent to copying the text.
Would there any way to write an equivalent class in C++ or similar RAII-based language which would guarantee memory safety regardless of threading usage, but would be not be needless inefficient when run from a single thread? The only approaches I'm aware of that such a method could be workable in C++ would be if either:
Whenever encountering an item whose "value" is larger than the previous maximum, the method copies the contents of the string; this would be slower than simply copying a reference. Further, I don't know how well this could maintain memory safety in the presence of improper threading usage.
Have the method receive a reference to a reference-counted pointer, and hold a variable of that type; when receiving a value which is larger than the previous maximum, atomically increment the reference count on the received pointer and atomically decrement the reference count on the previous maximum-item name; if the latter yields zero, release that name. This approach would seem safe, but on many platforms atomically increments and decrements would be excessively expensive for single-threaded usage, but would be necessary for memory safety in multi-threading scenarios.
Personally, I believe a good language/framework should support both RAII and GC, since each can handle very easily and efficiently some things which the other really can't handle at all. It's possible, though, that there would be some other approaches to handling such things in RAII that I'm unfamiliar with. Is there any way when using RAII to make a method like the above work efficiently when used in single-threading scenarios but also be usable in scenarios where a reference to a string created on one thread might then be exposed to other threads?
Note that unlike some other multi-threading RAII scenarios in which objects have a predictable lifetime, being consistently created in a producer thread and destroyed in a consumer thread (the subject of a related post), references to immutable objects like Strings
are often shared without any reference-holder being identifiable as an "owner", and without any way of knowing if or when whether any particular reference-holder might overwrite the last surviving reference to a string.