0

I have a vector with structs

Struct S {
    S( double a, double b ) : a_(a), b_(b) {}
    double a_;
    double b_;
    S(S&&) = default;   //ADDED
}

and I use emplace back to add instances of s to the vector

v.emplace_back( x, y );

Since it doesn't seem to be guaranteed that compilers will add a move constructor, I thought there is no harm in adding a default move constructor, so I added the line commented as ADDED. However, this seemed to have disabled the operator= as I get the compile error

/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/bits/stl_algo.h:868: error: use of deleted function ‘S& S::operator=(const S&)’
         *__result = _GLIBCXX_MOVE(*__first);
                   ^

I dont understand why that is the case. Is my implementation of S(S&&) the wrong way to do it?

EDIT: The error is thrown when using erase-remove

v.erase(std::remove_if(v.begin(), v.end(), deleteIf), v.end());
chrise
  • 4,039
  • 3
  • 39
  • 74

2 Answers2

3

A default copy assignment operator will be automatically provided (performing a memberwise copy) unless the class declares a copy assignment operator, deletes the copy assignment operator, or declares a move operation. The reason for this is that the compiler assumes that if you declare any move operation, it is likely that your class holds data which should not be copied, and so it forces you to implement the copy assignment operator yourself, in an attempt to enforce the Rule of Five.

There's an excellent chart showing when default constructors and assignment operators are provided in this slideshow, slide 30.

David Scarlett
  • 3,171
  • 2
  • 12
  • 28
2

Some older implementations of STL containers use the assignment operator when they resize the underlying containers. To resize, they allocate memory, default construct the initial objects, copy the objects over to the new container by using the assignment operator, and then release the previous objects.

On a related topic, if you are going to make an object Move-Constructible, you should also make it Move-Assignable.

Since the only data members in your struct are double's - primitive types that don't allocate resources - you don't need a move constructor for this struct.

RichS
  • 540
  • 1
  • 6
  • 12
  • But wouldnt that still mean that the structure gets created first, then copied and effectively created again? The structure I have in my example here is quite a bit smaller than the actual one (which also doesnt contain anything other than primitives, though – chrise Aug 08 '17 at 04:57
  • @chrise Yes, it would mean that. Some STL implementations work that way. Others don't. I prefer implementations favor move semantics if the object provides move-assignment operator or move-constructor. Check your STL implementation. :-) – RichS Aug 08 '17 at 04:59
  • So, adding "S& operator=(S&&)=default;" should fix my problem and also allow move construction? (the Struct may grow quite a bit, so I better get it done properly right now) – chrise Aug 08 '17 at 05:02
  • @chrise Yes, go ahead and add the move assignment operator and see what happens. You can also add a regular copy assignment operator too. – RichS Aug 08 '17 at 05:04
  • Well, compiler stops complaining. So, I take that as a good sign. For my understanding, one further question... this is basically equivalent to creating the structure and then passing it into emplace_back via std::move(s), right? – chrise Aug 08 '17 at 05:06
  • @chrise Yes, the parameter provided to emplace_back should either copy or move the object into the container. It will copy or move depending on implementation of the container and whether the object provides move semantics. All of the STL containers were originally designed years ago to be copy-in when inserting an object, and either get a reference or copy-out when accessing an element. Now we can do move for the copy-in. – RichS Aug 08 '17 at 05:14
  • Thanks for clarifying – chrise Aug 08 '17 at 05:18