Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2002-10-12 09:31:13


On Saturday, October 12, 2002, at 08:26 AM, Terje Slettebø wrote:

> "Effective C++", Item 21, "Use const whenever possible" argues for
> returning
> const UDTs, to avoid operating on temporaries, such as "(a * b)=c".
> This
> would also be illegal for built-in types. Why then not return "const
> T" in
> operators.hpp? The const is ignored for built-in types (as they have no
> "this"), but prevents the operation on temporaries, such as the above.

I think there are some existing valuable programming patterns for
performing non-const operations on temporaries. Consider:

#include <string>
#include <iostream>

int main()
{
    std::string s1("abc");
    std::string s2("123");
    std::string s3 = (s1 + s2).replace(s1.size()-1, 2, "C4");
    std::cout << s3;
}

abC423

Now certainly there are other ways to achieve this same effect. Maybe
those other ways or better, maybe they are not. But I assert that the
above code is viable and reasonable. And it would not be possible if
std::string + std::string returned a const std::string.

Imho, returning const T is a rather heavy handed approach to enforcing
a certain style. And one of the things that makes C++ so attractive
and powerful is that it supports so many styles.

The misuses that arise from returning a non-const T don't really seem
to occur in practice. How many times have you seen this outside of
contrived example code?

(s1 + s2) = s3;

It sticks out like a sore thumb. It just doesn't happen by accident.

Looking to the future, it is possible that non-const temporaries will
become vastly more useful than const temporaries (much more so than
demonstrated in my string example). I am specifically talking about
the move proposal:

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1377.htm

In this system, one can move from non-const temporaries, with no
additional syntax required over today's copy syntax:

s3 = s1 + s2; // temporary implicitly move assigned into s3

But moving from const temporaries is not allowed (for obvious reasons).

Now it is definitely premature to start designing around this proposal.
  It has not yet even been discussed in committee, and the final result
(if there is a result) will likely look very different. But there is
great interest in some kind of move facility throughout the C++
community. And the only proposed solution to date suggests there might
be an important use for non-const temporaries. So it just seems to me
that now is not the time to go sticking const on a lot of
return-by-value functions just to make sure clients don't write
insanely stupid code:

(s1 + s2) = s3;

And this is doubly true when there exists today viable, valid code that
may need non-const temporaries to work.

s3 = (s1 + s2).replace(s1.size()-1, 2, "C4");

> - "More Effective C++", Item 20, "Facilitate the return value
> optimization"
> argues for using the constructor in the return statement, rather than
> creating a named temp. The argument is that although NRVO is also now
> possible, RVO (unnamed temporary) has been around longer, and may
> therefore
> be more widely implemented. Thus, compilers implementing NRVO almost
> certainly implements RVO, but not necessarily the other way around.
> Given
> this, why isn't the following used in operators.hpp:
>
> friend T operator+( const T& lhs, const T& rhs )
> {
> return T(lhs)+=rhs;
> }

Assuming T::operator+= looks like:

T& T::operator+=(const T& rhs) { ... return this;}

The above approach is generally not optimizable via RVO. The return
statement sees a T&. Unless the compiler digs into op+=, it has no
reason to believe that the T& refers to the temporary. Thus a copy of
the object referred to by the T& must be made. If op+= returns by
value, then that is another story of course (and that is the case that
MEC++ #20 refers to).

-Howard


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk