By Bertwim van Beest


2011-11-03 21:03:27 8 Comments

I have a std::vector of objects of a certain class A. The class is non-trivial and has copy constructors and move constructors defined.

std::vector<A>  myvec;

If I fill-up the vector with A objects (using e.g. myvec.push_back(a)), the vector will grow in size, using the copy constructor A( const A&) to instantiate new copies of the elements in the vector.

Can I somehow enforce that the move constructor of class A is beging used instead?

3 comments

@Johan Lundberg 2012-01-14 19:50:00

You need to inform C++ (specifically std::vector) that your move constructor and destructor does not throw, using noexcept. Then the move constructor will be called when the vector grows.

This is how to declare and implement a move constuctor which is respected by std::vector:

A(A && rhs) noexcept { 
  std::cout << "i am the move constr" <<std::endl;
  ... some code doing the move ...  
  m_value=std::move(rhs.m_value) ; // etc...
}

If the constructor is not noexcept, std::vector can't use it, since then it can't ensure the exception guarantees demanded by the standard.

For more about what's said in the standard, read C++ Move semantics and Exceptions

Credit to Bo who hinted that it may have to do with exceptions. Also consider Kerrek SB's advice and use emplace_back when possible. It can be faster (but often is not), it can be clearer and more compact, but there are also some pitfalls (especially with non-explicit constructors).

Edit, often the default is what you want: move everything that can be moved, copy the rest. To explicitly ask for that, write

A(A && rhs) = default;

Doing that, you will get noexcept when possible: Is the default Move constructor defined as noexcept?

Note that early versions of Visual Studio 2015 and older did not support that, even though it supports move semantics.

@Lightness Races with Monica 2013-04-11 11:21:27

Out of interest, how does the impl "know" whether the value_type's move ctor is noexcept? Perhaps the language restricts the function call candidate set when the calling scope is also a noexcept function?

@Johan Lundberg 2013-04-11 13:48:04

@LightnessRacesinOrbit I assume it's just doing something such as en.cppreference.com/w/cpp/types/is_move_constructible. There can be only one move constructor so it should be clearly defined by the declaration.

@Johan Lundberg 2016-01-10 09:01:42

@LightnessRacesinOrbit, I've since learned that there is no (standard/useful) way to really know if there is a noexcept move constructor. is_nothrow_move_constructible will be true if there is a nothrow copy constructor. I'm not aware of any real case of expensive nothrow copy constructors so it's not clear that it really matters.

@AlastairG 2019-07-26 10:13:12

Doesn't work for me. My destructor, move constructor, and move assigment functions are all marked noexcept in both header and implementation, and when I do a push_back(std:;move) it still calls the copy constructor. I am tearing my hair out here.

@Johan Lundberg 2019-07-26 10:21:17

@alastairg please post a reproduce example for example at ideone. Perhaps you try to move from a const value or const reference? That gives you a copy.

@AlastairG 2019-07-26 12:52:13

@Johan I found the problem. I was using std::move() on the wrong push_back() call. One of those times when you are looking so hard for a problem that you don't see the obvious error right in front of you. And then it was lunchtime and I forgot to delete my comment.

@Nikola Benes 2013-03-14 19:12:50

Interestingly, gcc 4.7.2's vector only uses move constructor if both the move constructor and the destructor are noexcept. A simple example:

struct foo {
    foo() {}
    foo( const foo & ) noexcept { std::cout << "copy\n"; }
    foo( foo && ) noexcept { std::cout << "move\n"; }
    ~foo() noexcept {}
};

int main() {
    std::vector< foo > v;
    for ( int i = 0; i < 3; ++i ) v.emplace_back();
}

This outputs the expected:

move
move
move

However, when I remove noexcept from ~foo(), the result is different:

copy
copy
copy

I guess this also answers this question.

@Nikola Benes 2013-03-18 11:29:31

It seems to me that the other answers only talk about the move constructor, not about the destructor having to be noexcept.

@Nikola Benes 2013-05-31 10:42:50

Well, it should be, but as it turns out, in gcc 4.7.2 it wasn't. So this problem was, in fact, specific to gcc. It should be fixed in gcc 4.8.0, though. See related stackoverflow question.

@tower120 2017-10-30 15:53:41

It seems, that the only way (for C++17 and early), to enforce std::vector use move semantics on reallocation is deleting copy constructor :) . In this way it will use your move constructors or die trying, at compile time :).

There are many rules where std::vector MUST NOT use move constructor on reallocation, but nothing about where it MUST USE it.

template<class T>
class move_only : public T{
public:
   move_only(){}
   move_only(const move_only&) = delete;
   move_only(move_only&&) noexcept {};
   ~move_only() noexcept {};

   using T::T;   
};

Live

or

template<class T>
struct move_only{
   T value;

   template<class Arg, class ...Args, typename = std::enable_if_t<
            !std::is_same_v<move_only<T>&&, Arg >
            && !std::is_same_v<const move_only<T>&, Arg >
    >>
   move_only(Arg&& arg, Args&&... args)
      :value(std::forward<Arg>(arg), std::forward<Args>(args)...)
   {}

   move_only(){}
   move_only(const move_only&) = delete;   
   move_only(move_only&& other) noexcept : value(std::move(other.value)) {};    
   ~move_only() noexcept {};   
};

Live code

Your T class must have noexcept move constructor/assigment operator and noexcept destructor. Otherwise you'll get compilation error.

std::vector<move_only<MyClass>> vec;

@balki 2017-12-28 19:29:58

It is not necessary to delete copy constructor. If move constructor is noexcept, it will be used.

@tower120 2018-01-01 15:30:46

@balki It MAY be used. Standard does not REQUIRE this now. Here is discussion groups.google.com/a/isocpp.org/forum/…

Related Questions

Sponsored Content

6 Answered Questions

[SOLVED] What is std::move(), and when should it be used?

11 Answered Questions

[SOLVED] What is move semantics?

1 Answered Questions

Move semantics on individual vector elements

6 Answered Questions

2 Answered Questions

[SOLVED] C++ how to create move semantics for a class that is initialized as a vector

  • 2018-08-08 06:57:58
  • Liam Goodacre
  • 96 View
  • 0 Score
  • 2 Answer
  • Tags:   c++ vector move

1 Answered Questions

[SOLVED] Is the default Move constructor defined as noexcept?

0 Answered Questions

When vector grows dynamically, why its not using move constructor?

  • 2015-12-21 20:41:45
  • whitetiger
  • 76 View
  • 2 Score
  • 0 Answer
  • Tags:   c++ c++11 vector

1 Answered Questions

[SOLVED] Moving a vector of unique_ptr<T>

2 Answered Questions

[SOLVED] Extend std::vector to move elements from other vector type

1 Answered Questions

[SOLVED] Move semantics clarification

Sponsored Content