mardi 3 février 2015

How would move semantics improve "my way"?

Background


I read the following answers earlier today, and it felt like relearning C++, litterally.


What is move semantics?


What is the copy-and-swap idiom?


Then I wondered if I should change my "ways" to use these exciting features; the main concerns I have are for code efficiency and clarity (former slightly more important than the latter to me). This lead me to this post:


Why have move semantics?


with which I strongly disagree (I agree with the answer, that is); I don't think a smart use of pointers could ever make move semantics redundant, neither in terms of efficiency nor clarity.


Question


Currently, whenever I implement a non-trivial object, I roughly do this:



struct Y
{
// Implement
Y();
void clear();
Y& operator= ( const& Y );

// Dependent
~Y() { clear(); }

Y( const Y& that )
: Y()
{
operator=(that);
}

// Y(Y&&): no need, use Y(const Y&)
// Y& operator=(Y&&): no need, use Y& operator=(const Y&)
};


From what I understand from the two first posts I read today, I am wondering whether it would be beneficial to change to this instead:



struct X
{
// Implement
X();
X( const X& );

void clear();
void swap( X& );

// Dependent
~X() { clear(); }

X( X&& that )
: X()
{
swap(that);
// now: that <=> X()
// and that.~X() will be called shortly
}

X& operator= ( X that ) // uses either X( X&& ) or X( const X& )
{
swap(that);
return *this;
// now: that.~X() is called
}

// X& operator=(X&&): no need, use X& operator=(X)
};


Now, aside from being slightly more complicated and verbose, I don't see a situation in which the second (struct X) would yield a performance improvement, and I find that it is also less readable. Assuming my second code is using move-semantics correctly, how would it improve my current "way" of doing things (struct Y)?




Note 1: The only situation which I think makes the latter clearer is for "moving out of function"



X foo()
{
X automatic_var;
// do things
return automatic_var;
}
// ...
X obj( foo() );


for which I think the alternative using std::shared_ptr , and std::reference_wrapper if I get tired of get()



std::shared_ptr<Y> foo()
{
std::shared_ptr<Y> sptr( new Y() );
// do things
return sptr;
}
// ...
auto sptr = foo();
std::reference_wrapper<Y> ref( *ptr.get() );


is only slightly less clear, but as efficient.


Note 2: I really made an effort to make this question precise and answerable, and not subject to discussion; please think it through and don't interpret it as "Why are move-semantics useful", this is not what I am asking.


Aucun commentaire:

Enregistrer un commentaire