Re: Difference between static_cast<const A>(*this) and
static_cast<const A&>(*this)
On Wednesday, 14 August 2013 18:50:22 UTC+1, Melzzzzz wrote:
On Wed, 14 Aug 2013 10:24:24 -0700 (PDT)
James Kanze <james.kanze@gmail.com> wrote:
On Tuesday, 13 August 2013 17:28:51 UTC+1, Victor Bazarov wrote:
On 8/13/2013 11:56 AM, junyangzou wrote:
On Tuesday, August 13, 2013 11:41:33 PM UTC+8, James Kanze wrote:
[...] And the since the function where
you do the operation ends up returning a reference to data
inside this temporary, you end up with undefined behavior. It
. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
may seem to work, in simple cases, but you can't count on it.
I am using g++. And if the operation returns a reference to
data inside the temporary. It shouldn't affect the original
object book in any way. But the result is
: D
The object changed!
The behavior is *undefined*. Anything could happen, and among
valid outcomes can be that the original object changes. An
explanation to it might be that the compiler guesses what you
intended to do and changes the original object instead, but that's
still *undefined* and you should not rely on it. Read up on
undefined behavior.
That was my first reaction too. But when I tried to work out
what was really happening under the hood, I couldn't explain his
behavior, so I instrumented the class and tried it. There's a bug
in g++. Other compilers do make the copy.
What other compilers? I have tried clang , g++ and icpc they all
return 'D'.
Visual C++ copies. The standard makes it quite clear that
`static_cast` should copy in this case. For non-class types,
whether it copies or not doesn't make a difference; because the
results are an rvalue, there's no way a conforming program can
tell. But for a class type, the constructor must be called.
With a fully instrumented version (trace messages in all
constructors, destructors, etc.): the results are even more
interesting. G++ does do the copy, and modifies the copy,
but...
G++ uses a CoW implementation of std::string. When you call
a non-const version of operator[] on a string, it recognizes the
possibility of a possible modification, and "isolates" the
actual data, so that it is not shared, and will never be shared
in the future (until, at least, there is some operation which
would invalidate the returned reference). When you call the
const version, however, it doesn't do this. So the temporary
(and also your book2) share the same implementation, and when
you modify the temporary, you also modify the original, *and*
book2. Even with the reference, "book[0] = 'D';" also modifies
book2.
This raises an interesting point. If you call the const [],
cast away the const, and modify the object, is this undefined
behavior or not (assuming, of course, that the original object
was not const). If this behavior is defined, a CoW
implementation of std::string becomes almost impossible.
(For what it's worth, I've always done the opposite: the
const operator[] would call the non-const:
char& operator[]( int i )
{
return text[i];
}
char const& operator[]( int i ) const
{
return const_cast<TextBook*>( this )->operator[]( i );
}
Which would work, but would result in isolating the image when
it wasn't necessary.)
At any rate, your example is another point to consider in the
arguments for and against CoW.
--
James