2016-07-06 2 views
7

Ich habe eine uncodierbare Klasse. Kopieren wäre problematisch. Ich möchte Garantie, dass es nicht immer kopiert werden, so dass ich seine Copykonstruktor deleted:Wie erzwinge ich Kopierfehler, warum wird es nicht mit dem Konstruktor für gelöschte Kopien funktionieren?

class A { 
    public: 
    A(); 
    A(const A&) = delete; 
}; 

A fun() { 
    return A(); 
}; 

int main() { 
    A a = fun(); 
}; 

Leider g ++ wird das nicht kompilieren auf den Grund:

t.cc: In function ‘A fun()’: 
t.cc:8:12: error: use of deleted function ‘A::A(const A&)’ 
    return A(); 
      ^
t.cc:4:5: note: declared here 
    A(const A&) = delete; 
    ^
t.cc: In function ‘int main()’: 
t.cc:12:13: error: use of deleted function ‘A::A(const A&)’ 
    A a = fun(); 
      ^
t.cc:4:5: note: declared here 
    A(const A&) = delete; 
    ^

Aber Dies ist eine sehr klare Situation, in der Kopierfehler verwendet werden sollten, so dass der Kopierkonstruktor niemals aufgerufen werden sollte. Wieso ist es so?

+1

Warte bis C++ 17, vielleicht wird es garantiert –

+0

Whoops. Zur Antwort bewegt. –

+1

Jesper wiederholt Ihre Antwort nicht, Sie haben die bevorstehenden Änderungen bis zu unseren Kommentaren nicht erwähnt –

Antwort

9

Bis C++ 17 copy elision ist eine Optimierung, die der Compiler nicht benötigt, also müssen Klassen kopierbar sein, da der Compiler vielleicht kopieren möchte (auch wenn es das nicht tut). In C++ 17 wird in vielen Fällen eine Kopierfreigabe garantiert, und dann brauchen die Klassen keine Kopierzeichen.

Siehe auch:

http://en.cppreference.com/w/cpp/language/copy_elision

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

https://herbsutter.com/2016/06/30/trip-report-summer-iso-c-standards-meeting-oulu/ (das Bit über "Garantierte Kopie elision")

Sie könnten vielleicht den alten Trick erklärt die Kopie Konstruktor in Ihre Klasse, aber nicht wirklich implementieren? Das sollte dem Compiler gefallen, solange er den copy ctor nicht aufruft. Ich habe das nicht getestet, aber ich glaube, es sollte für Ihren Fall funktionieren, bis C++ 17 eintrifft.

8

Sie können Kopie Elision (noch) nicht erzwingen (sehen Sie andere Antworten).

Sie können jedoch einen Standard-Move-Konstruktor für Ihre Klasse angeben. Dadurch wird der Rückgabewert verschoben (und somit nicht kopiert), wenn RVO/NRVO nicht möglich ist. Dazu sollten Sie = default für Ihren Umzug Bauer hinzufügen:

class A { 
    public: 
    A() = default; 
    A(const A&) = delete; 
    A(A&&) = default; 
    A& operator=(A&&) = default; 
}; 

Example

+0

Ich kann den Down nicht verstehen, vor allem ohne Erklärung. – peterh

+1

@peterh Wahrscheinlich, weil es die von Ihnen gestellte Frage nicht beantwortet. – juanchopanza

+0

Ok, aber warum die Move-Konstruktoren benötigt werden? Der einzige Konstruktor, der in diesem Beispiel aufgerufen werden muss, ist der leere Konstruktor. Es passiert tatsächlich nichts. – peterh

7

Rückgabewert-Optimierung (RVO und NRVO) nicht die Forderung bedeutet, dass die betreffenden Arten von kopierbar oder bewegliche fallen gelassen wird. Diese Anforderung gilt unabhängig davon, ob Sie RVO erhalten oder nicht.

Der wahrscheinlichste Grund dafür ist, dass Kopierschutz nicht (derzeit) erzwungen wird. Es ist eine Optimierung, die stattfinden kann, und es wäre nicht sinnvoll für Code zu kompilieren oder nicht basierend darauf, ob diese Optimierung in einer bestimmten Implementierung angewendet wird.

In C++ 17 wird RVO unter bestimmten Umständen erzwungen, und die Anforderungen an die Kopierbarkeit und Beweglichkeit werden entfallen.

Verwandte Themen