3

Update: I use MSVC10, which doesn't not give me default move-semantics

Let's say I want to create a regular class with a couple of non-pod members;

class Foo {
NonPodTypeA a_;
NonPodTypeB b_;
}

As usual I implement a copy-constructor, and an assignment operator in which I utilize the copy-constructor:

Foo(const Foo& other) : a_(other.a_), b_(other.b_) {}
Foo& operator=(const Foo& other) { 
  Foo constructed(other);
  *this = std::move(constructed);
  return *this;
}

Then I implement the move-constructor and move-assignment, which utilizes std::swap instead of std::move for all member's as they might be written before move-semantics were available, as move-semantics is implemented, I can omit implementing a swap member function:

Foo(Foo&& other) {
  ::std::swap(a_, other._a);
  ::std::swap(b_, other._b);
}
Foo& operator=(Foo&& other) { 
  ::std::swap(a_, other._a);
  ::std::swap(b_, other._b);
  return *this;
}

And here goes my question; can something here be done more general, assuming I don't know anything about the members?

For example, the move-constructor is not compatible with const declared members, but if I implement the move constructor as Foo(Foo&& other) : a_(std::move(other.a_)), b_(std::move(other.b_)){} I cant be sure classes without move-semantics are not copied? Can I utilize the move-constructor in the move-assignment in some clever way?

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
  • 11
    As usual, you implement nothing. Let a_ and b_ take care of themselves. – Benjamin Lindley Mar 11 '12 at 22:19
  • 3
    There's more wrong with this than right. Among other things, don't fully qualify `std::swap`. – ildjarn Mar 11 '12 at 22:40
  • ADL should be used to invoke `swap`, not explicit qualification (unless that qualification is `boost::swap`, which will use ADL internally). – ildjarn Mar 11 '12 at 22:45
  • ildjarn: I still don't get it, if move-semantics is implemented in the class, std::swap will utilize it (at least in MSVC10) – Viktor Sehr Mar 11 '12 at 22:54
  • And if the data types have a custom swap, you don't _want_ to call `std::swap`, you want to call the custom one. – ildjarn Mar 11 '12 at 23:09
  • ildjarn: When datatypes have a swap member function, I assume std::swap is overloaded for that type – Viktor Sehr Mar 12 '12 at 07:31
  • 1
    @ViktorSehr: You're not allowed to add overloads to `namespace std`. That's why you want to pick the `swap` from the ADL namespace. – MSalters Mar 12 '12 at 09:39

2 Answers2

6

Erm, do nothing. All those things are generated automatically for you1. The only time you need to write them by hand is when the class handles resources (and then you need to follow the Rule of Three). This is also exactly how it was before. The only difference now is that after you considered the Rule of Three you may want to implement the move members either for semantic (i.e. making move-only objects) or performance (moves are usually faster than copies) reasons.


1. MSVC 10 doesn't generate move constructors automatically. In that case you may want to write the move members yourself :(

Community
  • 1
  • 1
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • 1
    "*MSVC 10 doesn't generate move constructors automatically, but that's a missing feature that will be added in MSVC 11.*" This is not my understanding. Do you have a link handy verifying this? – ildjarn Mar 11 '12 at 22:41
  • It's not going to be added in VC11. Think more along the lines of VC 11.1. – Nicol Bolas Mar 11 '12 at 22:43
  • 1
    @ildjarn oops, I got confused. It seems it's not in VC11 after all :( http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx – R. Martinho Fernandes Mar 11 '12 at 22:52
1

Given the limitations of MSVC10 and MSVC11 in that you have to write your own move constructors/move assignment operators the following is what I have. I based it on this video by Stephan T. Lavavej

http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Standard-Template-Library-STL-9-of-n

class Foo 
{
public:

    //Note: don't pass param by reference. Unified assignment operator
    Foo& operator=(Foo other)
    {
        other.swap(*this);
        return *this;
    }

    Foo(Foo&& other)
      : a_(std::move(other.a_),
        b_(std::move(other.b_){}

    Foo(Foo& other)
      : a_(other.a_),
        b_(other.b_){}

private:
    void swap(Foo& other)
    {
        using std::swap;
        swap(a_, other.a_);
        swap(b_, other.b_);
    }

private:
    NonPodTypeA a_;
    NonPodTypeB b_;
};
ildjarn
  • 62,044
  • 9
  • 127
  • 211
Alastair Taylor
  • 345
  • 1
  • 3
  • 10