|
Boost : |
From: David Abrahams (dave_at_[hidden])
Date: 2004-04-19 09:24:00
Andrea Torsello <torsello_at_[hidden]> writes:
> David Abrahams wrote:
>
>> 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.
>
> Oh, OK, if you assume that the compiler can always perform return value
> optimization, you are right. But I feel there is a difference in requiring
> the compiler to perform RVO on direct initialization from temporaries and
> requiring the compiler to perform it every time it is possible.
You appear to be making an argument about what's theoretically going
to work in correct, portable C++, based on the behavior of a
particular compiler implementation.
I am not requiring RVO unless you take what EDG accepts in strict mode
as the defintion of "standards conforming". I do not. EDG is
erroneous, IMO, in issuing that error, so we either turn off strict
mode or work around it by allowing its native RVO to work. GCC has a
much better example of what I consider a correct interpretation of the
standard in requiring that it be possible to construct a new temporary
rvalue from an existing one that will be bound to a reference (and
not "copy construct", as I point out in N1610).
> Using the explicit constructor technique #2 works even with compilers that
> do not support RVO, as long as you use the assignment constructor instead
> of the direct copy constructor.
Well, I challenge you to find a compiler that doesn't support at least
some RVO. But if you did find one, technique #1 is as good as
technique #2 in that respect. If you try the test with GCC and
-DBOOST_IMPLICIT_MOVE_CTOR_FOR_COPYABLE_TYPES you'll see that
technique 1 does 0 suboptimal copies and RVOs are suppressed, using
move construction instead. If you try it with technique 2, but no
explicit, and the same command-line you get 1 suboptimal copy (i.e. it
works without explicit). If you then add explicit you get 4
suboptimal copies because direct initialization can no longer
move. But who would want to suppress RVOs in favor of move
construction, anyway?
> You still need to convert to temporary in initializer lists, since
> you cannot use the assigment constructor there, but most likely you
> would have to do it anyway.
Is that just speculation? I can't understand why you'd make that
claim, since the CWG thinks that a prohibition on copying rvalues is
possible.
>> 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.
>
> Oh, right! There is probably no way around explicitly writing both
> constructors
I just got finished describing how it could be done using
implicit_cast. Did you not understand that?
> but you can avoid duplication by putting the constructor's body in a
> private member function and forward from both constructors to it.
> At least that is what I have been doing.
If it were that easy you could do it with macros by inserting a
surrounding brace pair and initializing a T const& there.
Unfortunately, it doesn't handle the initializer list and I almost
never have code in the ctor body.
-- 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