7
votes
\$\begingroup\$

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 <string>
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <memory>
#include <iterator>
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<Moveable> Moveables;
 Moveables v;
 generate_n(back_inserter(v), 1024, &generate_it);
 cout << v.size() << endl;
 string target = "zzz";
 auto that = find_if(v.begin(), v.end(), [target](const Moveables::value_type& it) -> 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;
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jun 22, 2012 at 17:17
\$\endgroup\$
1
  • \$\begingroup\$ I had posted another question very similar to this, but deleted it and replaced it with this one. The other question had used unique_ptr which ultimately was orthogonal to what I was really going for. \$\endgroup\$ Commented Jun 22, 2012 at 17:18

1 Answer 1

6
votes
\$\begingroup\$
  • 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.

answered Jun 23, 2012 at 12:37
\$\endgroup\$
3
  • \$\begingroup\$ +1: various replies. 1) The destructor was an artifact of my testing durig development. Since its implementation was trivial, and the tor was public, I've removed it entirely. \$\endgroup\$ Commented Jun 26, 2012 at 16:35
  • \$\begingroup\$ 2) noexcept is not supported by MSVC10. Sad. \$\endgroup\$ Commented Jun 26, 2012 at 16:38
  • \$\begingroup\$ 3) Fixed generate_it 4) fixed sort call. These were simply part of the harness, but it's important that the whole thing is correct. \$\endgroup\$ Commented Jun 26, 2012 at 16:40

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.