3

I had some problem implementing the move constructor for an element in my std::array in my project in visual studio 2013.

So I tried making a minimal example in notepad++ that I compiled with g++ 5.3.0.
Only to find that in g++ I could do what I was trying

example g++:

#include <iostream>
#include <array>

using namespace std;

struct A{
    A() = default;
    A(const A&)
    {
        cout << "copy constructed" << endl;
    }
    A(A&&)
    {
        cout << "move constructed" << endl;
    }
};

class B{
public:
    B(array<A, 2>&& a)
      : m_a(std::move(a))
    {}
private:
    array<A, 2> m_a;
};

int main(){
    A foo;
    cout << "=========1===========" << endl;
    array<A, 2> a = { { foo, std::move(foo) } };
    cout << "=========2===========" << endl;
    B b(std::move(a));
    cout << "=========3===========" << endl;
    array<A, 2> a_second = std::move(a);
    return 0;
}

Output:

=========1===========
copy constructed
move constructed
=========2===========
move constructed
move constructed
=========3===========
move constructed
move constructed

When I tried the (practically) the same code in visual studio 2013 the result was different:

Output:

=========1===========
copy constructed
move constructed
=========2===========
copy constructed
copy constructed
=========3===========
copy constructed
copy constructed

How can I use the move constructor in visual c++ and why does visual c++ refuse to use him here?

turoni
  • 1,345
  • 1
  • 18
  • 37

2 Answers2

4

This is a bug in MSVS 2013. MSVS 2013 does not generate implicit move constructors. If you run it in a MSVS 2015 or 2017 you get the same output.


I would also like to point out that

B(array<A, 2>& a) : m_a(std::move(a))

Is not how you want to move an object into B. If you want B to take over the array you should have

B(array<A, 2>&& a) : m_a(std::move(a))

This means that instead of using

B b(a);

you have to use

B b(std::move(a));

and now you can clearly see that a has been moved from in main.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • I just edited in better constructor for B. Is there any way I can get the same result in MSV2013? – turoni Jul 31 '17 at 12:44
  • 1
    @turoni Unfortunately no. It just isn't built to work correctly. – NathanOliver Jul 31 '17 at 12:46
  • @turoni You can write a type wrapping `std::array`, like inherited, and manually implement the move constructor. MSVC2013 never writes a proper move ctor for you and doesn't let you `noexcept`. MSVC2017 requires a proper `noexcept` to work in `std::vector`s properly. It is a large pain. – Yakk - Adam Nevraumont Jul 31 '17 at 12:48
2

Visual studio 2013 isn't fully compatible with C++11. Move support for std containers is one of those "not fully implemented" parts. Your example works fine for the latest version of VS2017, see at Rextester.

P.S. Here you can get detailed information about support for C++ features in various compilers.

Vasiliy Galkin
  • 1,894
  • 1
  • 14
  • 25