2015-12-31 15 views
16

Ich habe einen Typ, den ich den Kopierkonstruktor gelöscht habe, und ich hätte gerne eine vector dieses Typs, also muss ich alle Elemente über emplace_back erstellen. Aber emplace_back scheint einen Kopierkonstruktor zu benötigen, da der Compiler eine Warnung gibt, dass emplace_back nicht instanziiert werden kann, weil der Kopierkonstruktor gelöscht wurde. Warum benötigt es einen Kopierkonstruktor? Ich dachte, der ganze Sinn von emplace_back war, die vector zu bauen, ohne etwas zu kopieren. Kann ich sogar eine vector von Objekten haben, die keinen Kopierkonstruktor haben?Warum funktioniert diese Verwendung von emplace_back mit dem Konstruktor für gelöschte Kopien nicht?

class MyType { 
public: 
    MyType(std::array<double, 6> a) {} 
    MyType(const MyType& that) = delete; 
}; 

int main() { 
    std::vector<MyType> v; 
    std::array<double, 6> a = {1,2,3,4,5,6}; 
    v.emplace_back(a); 
} 

Compiler ist clang/llvm.

+0

http://cpp.sh/9v5w hier funktioniert nicht –

+0

hier auch http://goo.gl/eLUPjR –

+0

'emplace_back' brauchen nicht die Kopie Konstruktor, aber wenn die Kapazität von Vektor ist nicht genug zu speichern neues Element, Vektor muss sein Element neu zuweisen, dies erfordert den Konstruktor copy/move. Durch das Löschen des Kopierkonstruktors verhindern Sie auch, dass der Standardbewegungskonstruktor generiert wird. In diesem Fall deklarieren Sie einen Move-Konstruktor möglicherweise – Danh

Antwort

20

Wenn der interne Speicher vector wächst, müssen die Elemente aus dem alten Speicher in den neuen verschieben. Durch das Löschen des Kopierkonstruktors verhindern Sie auch, dass der Standardbewegungskonstruktor generiert wird.

9

Um emplace_back aufrufen zu können, sollte Ihr Typ entweder EmplaceConstructible oder MoveInsertible lauten. Sie müssen Ihrer Klasse einen Verschiebungskonstruktor geben, wenn Sie den Kopierkonstruktor gelöscht haben. (Check this für Anforderungen von emplace_back)

MyType(MyType &&a) {/*code*/} //move constructor 
0

Wenn Sie versuchen, diesen Code auszuführen:

// Example program 
#include <iostream> 
#include <string> 
#include <array> 
#include <vector> 
class MyType { 
public: 
    MyType(std::array<double, 6> a) { 
     std::cout<< "constructed from array\n"; 
     } 
    MyType(const MyType& that){ 
      std::cout<< "copy\n"; 
    } 

    MyType(MyType&& that){ 
      std::cout<< "move\n"; 
    } 
}; 

int main() { 
    std::vector<MyType> v; 
    std::array<double, 6> a = {1,2,3,4,5,6}; 
    v.emplace_back(a); 
} 

Sie folgendes Ergebnis:

von Array konstruiert

Live Demo

Es ist klar, dass nur die constructor von std::Array aufgerufen wird. Also keine Notwendigkeit für copy constructor. Aber in der gleichen Zeit, wenn Sie deleted die copy constructor, wird der Compiler einen Fehler auslösen (zumindest auf zwei Compiler habe ich versucht firstsecond). Ich denke, dass einige Compiler die Existenz von copy constructor überprüfen werden, wenn emplace_back verwendet wird, auch wenn es in diesem praktischen Fall nicht notwendig ist, während andere dies nicht tun. Ich weiß nicht, was hier Standard ist (welcher Compiler richtig oder falsch ist).

+1

Das Problem ist, dass "emplace_back" kann der Vektor zu wachsen, die die Objekte innerhalb beweglich sein müssen. Und da 'MyType' einen vom Benutzer deklarierten Kopierkonstruktor hat, wird kein Move-Konstruktor generiert und die Klasse ist weder kopierbar noch verschiebbar. – Angew

+1

aber zumindest in diesem Fall wurde keine Kopie oder Bewegung aufgerufen. Was ist der Unterschied? –

+0

@HumamHelfawi Es könnte eventuell erforderlich sein. Was bedeutet, dass es einen Code gibt, der für diesen Fall zur Verfügung steht. Und dazu müssen entweder der Move-Konstruktor und der Copy-Konstruktor zur Kompilierzeit vorhanden sein. – bashrc