computer hardware instead of an abstract machine model. Thus we settle for the following guidelines:
1. For an algorithm
2. All container or iterator complexity specifications refer to amortized complexity. An individual operation may take longer than specified. But any sufficiently long sequence of operations on the same container or iterator will take at most as long as the corresponding sum of the specified operation costs.
3. Algorithms specify either worst-case or average case performance, and identify which. Unless otherwise stated, averages assume that container elements are chosen from a finite type with more possible values than the size of the container, and that container elements are independently uniformly distributed.
4. A complexity specification for an operation
5. If operations are more expensive than assumed by a function
To make this precise, assume
Strings in SGI STL
This is an attempt to answer some of the questions related to the use of strings with SGI STL.
There are several problems, but the most serious ones relate to the specification for lifetimes of references to characters in a string. The second committee draft disallows the expression s[1] == s[2] where s is a nonconstant string. This is not simply an oversight; current reference counted implementations may fail for more complicated examples. They may fail even for s[1] == s[2] if the string s is simultaneously examined (merely examined, not necessarily modified) by another thread. It is hard to define precisely what constitutes a correct use of one of the current reference counted implementation.
This problem was partially addressed at the July 1997 meeting of the C++ standardization committee; the solution was to adopt more complicated rules about reference lifetimes. Unfortunately, these new rules still do not address the multi-threading issues.
A related problem was pointed out in the French national body comments on the second committee draft. The following program produces the wrong answer for most reference counted
main() {
string s('abc');
string t;
char& c(s[1]);
t = s; // Data typically shared between s and t.
c = 'z'; // How many strings does this modify?
if (t[1] == 'z') {
printf('wrong
');
} else {
printf('right
');
}
}
The draft standard (as well as common sense) says that updating a reference to one of
The only known way for a reference-counted implementation to avoid this problem is to mark a string as unsharable whenever there might be an existing reference or iterator to that string. That is, whenever a program obtains a reference or an iterator to a string (
This is a drastic solution: since almost all ways of referring to characters involve references or iterators, this solution implies, in effect, that the only strings that can be reference-counted are the ones that are never used. In practice, then, a reference counted implementation of
A different solution is to abandon the goal of reference-counted strings altogether, and to provide a non- reference-counted implementation of
In this implementation, basic_string does not use reference counting. I have been using a reference counted implementation, and it works fine. Why haven't I seen problems?
The current implementations do work correctly, most of the time: preserving a reference to a character in a string is uncommon. (Although preserving iterators to strings may be more frequent, and exactly the same issues apply to iterators.) Some less contrived sequential programs also fail, though, or else behave differently on different platforms.
Multi-threaded applications that use a reference counted