Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2004-04-19 06:53:45


Andrea Torsello <torsello_at_[hidden]> writes:

> No, in some implementations you can just not provide the explicit
> constructor at all (at least gcc works well without it). If you do
> that you do not have the direct initialization problem anymore. I
> used the explicit keyword to use my approach with compliers like
> Comeau that do not like if you do not provide a X(X const &)
> constructor. I actually omitted to say this on the first iteration
> of the sample code because I though I needed to focus on the general
> approach. In the library I use with gcc I simply do not provide the
> explicit copy ctor at all.

I really understood that's what you were saying. My point was that if
you just leave out the fancy "move ctor" overloads and provide the
X(X const&) ctor with Comeau, the RVOs kick in and you don't get any
suboptimal copies... except when using direct initialization. Since
your technique punts on moving in that case anyway, it seems like
there's really zero advantage to using the explicit copy ctor at all.

>> In non-strict mode (and on Intel 8/win32) technique 2 seems to
>> generate copies when constructing from const rvalues whereas
>> technique 1 does not.
>
> Yes, actually different compilers seem to act differently here.
> Since the compiler is free to copy const rvalues to non-const
> rvalues and optimize the copy away, I would consider returning a const
> temporary an odd thing to do. I am curious: does anyone have a use-case
> for it?

I doubt it; it doesn't seem like a very important case. It could be
used to have some effects on overload resolution I suppose, but it's
hard to imagine that being useful in real code.

>> Not having a real T const& parameter for const lvalues makes writing
>> overloads tricky. I was able to make the macros transparent for
>> operator=, but because of initializer lists there's no way to do the
>> same thing for constructors. const_lvalue<T> now has a conversion to
>> T const&, so you can use boost::implicit_cast<T const&>(rhs) to get
>> a reference to the argument with uniform syntax.
>
>
> I am not sure I understood what you are saying here.
> Can you rephrase it please?

The point is that if you want to use macros (or copy-and-paste) to
generate the two overloads for (T& rhs) and (const_lvalue<T> rhs), you
can have a problem trying to re-use the initializer list and body of
the function because T& and const_lvalue<T> have different interfaces.
With the appropriate conversion operator on const_lvalue,
implicit_cast<T const&>(rhs) is the same thing in both cases and can
be used to make initializer lists and bodies that can be reused.

Technique 1 essentially uses (T& rhs) and (T const& rhs) signatures,
so that's not a problem.

>> Results
>> -------
> [...]
>
> We should probably try and not provide the explicit copy ctor with
> compilers that do not complain about it. I feel that this way some
> of the suboptimal copies will go away.

The suboptimal copies in my measurements for "technique 2" appear
without any use of "explicit" on the copy ctor. Please, though, take
a close look at what the code is doing to see if I've misinterpreted
your intention. In particular, run the move.cpp test, then turn on
-DBOOST_IMPLICIT_MOVE_CTOR_FOR_COPYABLE_TYPES and edit the code to
make the ctor explicit. I think you'll see that it puts us back where
we started.

P.S. My tests are really the best part of what I've done on this; they
reveal so much about what the compilers are doing, and tend to find
problem cases by testing move-only types. I really want to encourage
you to try whatever move ideas you may have in the testing framework
I've set up.

-- 
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

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