2016-11-07 1 views
2

Ceci est une classe de démonstration. Je ne veux pas que ma classe soit copiée, donc je supprime le constructeur de copie. Je veux que vector.emplace_back utilise ce constructeur 'MyClass (Type type)'. Mais ces codes ne compileront pas. Pourquoi?Vecteur C++ emplace_back appels copy constructeur

class MyClass 
{ 
public: 
    typedef enum 
    { 
     e1, 
     e2 
    } Type; 
private: 
    Type _type; 
    MyClass(const MyClass& other) = delete; // no copy 
public: 
    MyClass(): _type(e1) {}; 
    MyClass(Type type): _type(type) { /* the constructor I wanted. */ }; 
}; 

std::vector<MyClass> list; 
list.emplace_back(MyClass::e1); 
list.emplace_back(MyClass::e2); 
+0

Pour résoudre le problème, ajoutez un constructeur de déplacement par défaut. Si vous ne voulez pas non plus, vos options sont plus limitées –

+0

Merci, j'ai choisi d'écrire un constructeur de mouvement. – wqyfavor

Répondre

5

Le constructeur de copie est requise par vector afin qu'il puisse copier l'élément quand il a besoin de développer son stockage.

Vous pouvez lire le document pour vector

T doivent satisfaire aux exigences de CopyAssignable et CopyConstructible. (jusqu'à C++ 11)

Les exigences qui sont imposées aux éléments dépendent des opérations réelles effectuées sur le conteneur . Généralement, il est requis que le type d'élément soit un type complet et qu'il réponde aux exigences de Effaçable, mais de nombreuses fonctions membres imposent des exigences plus strictes. (Puisque C de 11) (jusqu'à ce que C++ 17)

Les exigences qui sont imposées sur les éléments dépendent des opérations effectuées réelles sur le récipient. Généralement, il est nécessaire que le type d'élément soit conforme aux exigences de Effaçable, mais de nombreuses fonctions membres imposent des exigences plus strictes. Ce conteneur (mais pas ses membres ) peut être instancié avec un type d'élément incomplet si l'allocateur satisfait aux exigences d'exhaustivité de l'allocateur.

Certains exploitation forestière peut vous aider à comprendre ce qui se passe

For this code

class MyClass 
{ 
public: 
    typedef enum 
    { 
     e1 = 1, 
     e2 = 2, 
     e3 = 3, 
    } Type; 
private: 
    Type _type; 
public: 
    MyClass(Type type): _type(type) { std::cout << "create " << type << "\n"; }; 
    MyClass(const MyClass& other) { std::cout << "copy " << other._type << "\n"; } 
}; 

int main() { 
    std::vector<MyClass> list; 
    list.reserve(2); 
    list.emplace_back(MyClass::e1); 
    list.emplace_back(MyClass::e2); 
    list.emplace_back(MyClass::e3); 
} 

La sortie est

create 1 
create 2 
create 3 
copy 1 
copy 2 

Vous pouvez donc emplace_back n'utilise le constructeur souhaité pour créer l'élément et appelez le constructeur de copie quand il a besoin d'augmenter le stockage. Vous pouvez appeler reserve avec suffisamment de capacité à l'avance pour éviter d'avoir à appeler le constructeur de copie.


Si pour une raison quelconque, vous ne voulez vraiment pas à copier constructible, vous pouvez utiliser std::list au lieu de std::vector comme list est mis en œuvre en tant que liste chaînée, il n'a pas besoin de déplacer les éléments.

http://coliru.stacked-crooked.com/a/16f93cfc6b2fc73c

+0

Je suis nouveau en C++, merci. – wqyfavor

+0

Vous avez mis en gras une partie du comportement pré-C++ 11. Le reste de votre devis explique que le comportement a changé en C++ 11, en particulier la partie en gras ne s'applique plus. –

+0

@Bryan Chen Je pense que vous voulez dire cela http://coliru.stacked-crooked.com/a/2dea811906d90d84 –

0

Juste une précision pour la question. Si nous ne voulons pas que des objets copient la construction à utiliser lors d'une réallocation du conteneur, il est en effet possible avec un constructeur de déplacement mais seulement s'il a la spécification noexcept.

Les conteneurs refusent de déplacer des éléments de construction si le constructeur peut déclencher une exception car cela pourrait entraîner un conteneur dans un état incorrect qui ne peut pas être nettoyé. C'est la raison pour laquelle il est généralement recommandé de spécifier un constructeur de mouvement comme étant non nul quand nous sommes sûrs qu'il ne lâchera aucune exception.