Question La réallocation du vecteur utilise la copie au lieu du constructeur de déplacement


Bonjour, j'ai créé une classe Foo avec un constructeur de déplacement noexcept en utilisant gcc 4.7 et définissez la taille de la réserve de vecteurs à 2 pour qu'elle réattribue la taille lors de l'ajout du 3ème élément. Il semble que cela appelle le constructeur de copie au lieu du constructeur de déplacement. Est-ce que j'ai râté quelque chose?

#include <vector>
#include <iostream>

class Foo
{
  public:
  Foo(int x) : data_(x)
  {
    std::cout << " constructing " << std::endl;
  }

  ~Foo()
  {
    std::cout << " destructing " << std::endl;
  }

  Foo& operator=(const Foo&) = default;
  Foo& operator=(Foo&&) = default;

   Foo(Foo&& other) noexcept : data_(std::move(other.data_))
   {
    std::cout << " Move constructing " << std::endl;
   }

   Foo(const Foo& other) noexcept :  data_(other.data_)
   {
    std::cout << " Copy constructing " << std::endl;
   }

  private:
  int data_;
};


int main ( int argc, char *argv[])
{
  std::vector<Foo> v;
  v.reserve(2);
  v.emplace_back(1);
  std::cout << "Added 1" << std::endl;
  v.emplace_back(2);
  std::cout << "Added 2" << std::endl;
  v.emplace_back(3);
  std::cout << "Added 3" << std::endl;
  std::cout << "v size: " << v.size() << std::endl;
}

sortie:

 constructing 
Added 1
 constructing 
Added 2
 constructing 
 Copy constructing 
 Copy constructing 
 destructing 
 destructing 
Added 3
v size: 3
 destructing 
 destructing 
 destructing 

12
2017-09-06 10:26


origine


Réponses:


Après avoir bricolé un peu avec GCC 4.7 et 4.8, il semble bien que ce soit un bogue dans 4.7, qui n'apparaît que lorsque le destructeur de la classe est ne pas marqué noexcept:

struct Foo {
  Foo() {}
  ~Foo() noexcept {}
  Foo(Foo&&) noexcept { std::cout << "move constructor" << std::endl; }
  Foo(const Foo&) noexcept { std::cout << "copy constructor" << std::endl; }
};

int main() {
  std::vector<Foo> v;
  v.reserve(2);
  v.emplace_back();
  v.emplace_back();
  v.emplace_back();
}

GCC 4.7 affiche:

move constructor
move constructor

Si on enlève noexcept du destructeur:

struct Foo {
  Foo() {}
  ~Foo() {}
  Foo(Foo&&) noexcept { std::cout << "move constructor" << std::endl; }
  Foo(const Foo&) noexcept { std::cout << "copy constructor" << std::endl; }
};

GCC 4.7 affiche:

copy constructor
copy constructor

GCC 4.8 utilise le constructeur de déplacement dans les deux cas.


13
2017-09-06 10:49