Boost logo

Boost :

Subject: Re: [boost] [move] problem with msvc-10 (BOOST_MOVABLE_BUT_NOT_COPYABLE)
From: Jeffrey Lee Hellrung, Jr. (jhellrung_at_[hidden])
Date: 2010-11-25 01:57:31


On 11/24/2010 10:33 PM, Vicente Botet wrote:
> Oliver Kowalke-2 wrote:
>> -------- Original-Nachricht --------
>> Betreff: [move] problem with msvc-10 (BOOST_MOVABLE_BUT_NOT_COPYABLE)
>> Datum: Wed, 24 Nov 2010 20:56:46 +0100
>> Von: Oliver Kowalke<oliver.kowalke_at_[hidden]>
>> An: boost_at_[hidden]
>>
>> Hi,
>> msvc-10 has some problems with boost.move.
>> linker error: LNK2019: unresolved symbol "private __cdecl X::X(class X
>> const&)"
>>
>> Example doc_file_descriptor.cpp (uses BOOST_MOVABLE_BUT_NOT_COPYABLE)
>> does not compile too.
>>
>> g++-4.4.5 accepts the code.
>>
>> ?
>>
>> X X::create()
>> {
>> boost::shared_ptr< impl_t> impl( new impl_t() );
>> return X( impl);
>> }
>>
>
> Shouldn't this function use boost::move?
>
> X X::create()
> {
> boost::shared_ptr< impl_t> impl( new impl_t() );
> return boost::move( X( impl) );
> }

I don't think that works in C++03 since boost::move takes its parameter
by reference-to-non-const; i.e., one should get a compiler error about
binding the temporary X to templated argument T& (I suppose MSVC might
let it slide since it allows such binding...). It could work in C++0x,
depending on the declaration of boost::move, but it ultimately doesn't
change the semantics of the function (i.e., the move constructor, not
the copy constructor, will be invoked either way).

>> int main(int argc, char * argv[])
>> {
>> X x( X::create() );
>> return 0;
>> }
>>
>
> Shouldn't this declaration use boost::move?
>
> X x( boost::move(X::create()) );

Same comments here.

> Or shouldn't X::create returns a rvalue to X?

You'd have to return a reference to a local, so that's a no go. I think
the original X::create definition is correct.

Looking back at the original message, I think a problem is in the
definition of the move assignment operator:

BEFORE:
X & X::operator=( BOOST_RV_REF( X) other)
{
     if ( this != & other)
     {
         X tmp( other);
         swap( tmp);
     }
     return * this;
}

AFTER (corrected):
X & X::operator=( BOOST_RV_REF( X) other)
{
     if ( this != & other)
     {
         X tmp( boost::move(other) ); // must explicitly move other
         swap( tmp);
     }
     return * this;
}

The BEFORE code works in C++03 emulation mode since the expression
"other" actually is an emulated rvalue reference. On the other hand, in
C++0x, the expression "other" is an lvalue reference, even though other
is declared as an rvalue reference, thus the BEFORE code actually uses
the copy constructor rather than the move constructor (and hence the
linker error).

The above behavior of the expression "other" is to help prevent
unintended moves.

I don't have access to MSVC10, so, Oliver, see if the above change gets
rid of the linker error.

- Jeff


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