A C++ Immutable String class
blog.reliablecpp.com
blog.reliablecpp.com
[21.4.1.4] does say "Every object of type basic_string<charT, traits, Allocator> shall use an object of type Allocator to allocate and free storage for the contained charT objects as needed", but that "as needed" most definitely leaves the door open for a COW implementation.
The only other part that I can see that may preclude a COW implementation is the postconditions specified for copy operations [21.4.2], which says data() returns a pointer which "points at the first element of an allocated copy of the array whose first element is pointed at by str.data()". Again though, "allocated copy" doesn't necessarily mean "a copy I just allocated". When I go and get a copy of a book I don't literally go and copy it.
In fact the standard specifies that the move constructor leave the source value "in a valid state with an unspecified value"... which again suggests you could use COW and have the source argument return the same value it had before you moved from it.
In the latest C++14 draft though (N3690), you're right, it is explicitly prohibited because "Invalidation is subtly different with reference-counted strings".
The non-const operator[] in a COW string requires making a copy of the string if the ref count > 1 which invalidates references and violates this paragraph.
The author also has a rather [confusing article][1] about immutable vs const, that I would discredit personally. He claims that objects accessed via reference to const can modify themselves, which is not true, as you can only access const functions through a const reference.
[1]: http://blog.reliablecpp.com/2013/09/immutable-vs-const/
The example is misleading because there isn't any reason why you would be concerned with such a distinction in this case.
This isn't so much an issue for functions, where the caller is stopped while the callee runs, but it needs to be borne in mind for longer-lived objects that take const references - or, indeed, const pointers - to objects that have longer lifetimes again. (I don't think multithreading need be introduced for this to be an issue.)
There's quite a difference between an object that could change and one that won't, if you're considering caching values across method calls, or setting up the referring object based on the referred object's current state, etc.
You really do not understand what "const" means in C++.
If what you said were true, a whole class of optimizations would be possible that are not currently possible. For example, consider this silly function:
void f(const int *x) {
int y = *x;
g();
if (y == *x) h();
}
If what you said were true, this would be able to optimize away the call to h() completely, but if you compile the function with maximum optimization you will see that this is not the case. Why not? Because the caller could look like this: int val = 0;
void g() { val = 1; }
int main() { f(&val); } std::string const s("Hello"); #include <string>
#include <iostream>
// not your code
void innocentF(std::string const& s) {
(const_cast<std::string&>(s)) += std::string(" I'm evil.");
}
// your code
int main() {
std::string const s("hello world.");
innocentF(s);
std::cout << s << std::endl; // hello world. I'm evil.
return 0;
}7.1.5.1/4: Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.
const_cast is not undefined behavior, but modifying a const object is.
But what I meant in the above comment is that you can't accidentally type "const_cast". So when you type it, you're on your own. And there is nothing wrong with it in C++ world - if you explicitly state that you want to shoot yourself in the foot, the compiler will just listen to your orders (maybe with some warnings).
Also, I hope you're not suggesting immutability is a Javaism...
Back then when I graduated (1999), at least in Portugal there were lots and lots of languages to use for assignments, during the degree (5 years long).
I don't mention Java ;)
The problem with strings being mutable by default is that one has to do a lot of defensive copying to avoid unexpected behavior. Mutable strings do have their place, inside a function that's building up a string, before that string is visible to any other part of the program. But it shouldn't be the default.
See also: "The Value of Values" by Rich Hickey (http://www.infoq.com/presentations/Value-Values)