HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Canonical Implementation of Move Semantics

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
movecanonicalimplementationsemantics

Problem

I am trying to compose an illustrative example which shows how to implement move semantics on an object that will be stored in a vector.

Please consider the following code, which is my illustrative example so far. It is designed to be a canonical, pedantically correct implementation of an object that implements move semantics, does not implement copy semantics, and can be stored in a vector<> (Where T is Moveable, below). How did I do?

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

class Moveable
{
public:
    string foo_;
    string bar_;

    Moveable(Moveable&& rhs) : foo_(std::move(rhs.foo_)), bar_(std::move(rhs.bar_)) {}  // move construction
    Moveable(const string& foo) : foo_(foo) {};             // convert construction
    Moveable& operator=(Moveable&& rhs)     // move assignment
    {
        foo_ = std::move(rhs.foo_);
        bar_ = std::move(rhs.bar_);
        return * this;
    }
private:
    Moveable(const Moveable&);              // not defined, not copy-constructible
    Moveable& operator=(const Moveable&);   // not defined, not copy-assignable
    Moveable();                             // not defined, not default constructible
};

Moveable generate_it()
{
    static string foo ;
    if( foo.empty() || foo[0] == 'z' )
        foo.insert(0, 1, 'a');
    else
        foo[0]++;
    return foo;
}

int main()
{
    typedef vector Moveables;
    Moveables v;
    generate_n(back_inserter(v), 1024, &generate_it);
    cout  bool
    {
        return it.foo_ == target;
    });

    if( that != v.end() )
        v.erase(that);

    sort(v.begin(), v.end(), [](const Moveables::value_type& lhs, const Moveables::value_type& rhs) -> bool
    {
        return lhs.foo_ > rhs.foo_;
    });
    cout << v.size() << endl;
}

Solution

-
One small error: Mark the move constructor as noexcept, otherwise there are situations where it won’t be used. The linked case is different since the class has a copy-constructor, yet I can imagine that there are still situations where it matters, especially since your copycon isn’t deleted, just private and undefined.

-
Why is the destructor virtual? If the example is supposed to be minimal then this might be distracting.

-
In generate_it:

return std::move(Moveable(foo));


The std::move here is redundant, since you are returning a temporary. What’s more, the explicit constructor call is redundant too, since the constructor isn’t marked as explicit. Just return foo; will do.

-
The find_if call could be replaced by vanilla find, using temporary construction again:

auto that = find(v.begin(), v.end(), target);


-
Finally, in the sort call, why aren’t the arguments declared const&? Granted, makes the line even longer as it stands this is inconsistent with the const-correctness illustrated in the find_if call.

Code Snippets

return std::move(Moveable(foo));
auto that = find(v.begin(), v.end(), target);

Context

StackExchange Code Review Q#12954, answer score: 6

Revisions (0)

No revisions yet.