Wie erzwinge ich das Entfernen von Kopien, warum funktioniert es nicht mit dem gelöschten Kopierkonstruktor?

Lesezeit: 4 Minuten

Wie erzwinge ich das Entfernen von Kopien warum funktioniert es
Peterh

Ich habe eine nicht kopierbare Klasse. Das Kopieren wäre problematisch. Ich möchte Garantie dass es niemals kopiert wird, also habe ich seinen Kopierkonstruktor erstellt deleted:

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

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

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

Leider wird g ++ dies aus folgendem Grund nicht kompilieren:

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;
     ^

Dies ist jedoch eine sehr klare Situation, in der das Entfernen von Kopien verwendet werden sollte, sodass der Kopierkonstruktor niemals aufgerufen werden sollte. Wieso ist es so?

  • Warten Sie bis C++17, vielleicht wird es garantiert

    – Piotr Skotnicki

    6. Juli 2016 um 13:13 Uhr

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

    – Piotr Skotnicki

    6. Juli 2016 um 13:21 Uhr

  • @PiotrSkotnicki Entschuldigung, ich habe Ihre Kommentare nicht gelesen.

    – Juanchopanza

    6. Juli 2016 um 13:22 Uhr

  • Die Lösung, die ich in diesem Fall am häufigsten gesehen habe, ist, die Klasse zu verschieben oder, wenn sie nicht verschiebbar ist, zurückzukehren std::unique_ptr<A>.

    – Chris Beck

    6. Juli 2016 um 17:36 Uhr

Wie erzwinge ich das Entfernen von Kopien warum funktioniert es
Jesper Juhl

Bis C++17 ist Copy Elision eine Optimierung, die der Compiler nicht durchführen muss, daher müssen Klassen kopierbar sein, da der Compiler möglicherweise kopieren möchte (auch wenn dies eigentlich nicht der Fall ist). In C++17 wird das Entfernen von Kopien in vielen Fällen garantiert, und dann benötigen Klassen keine Kopierctors.

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 Kopierentfernung”)

Sie könnten vielleicht den alten Trick anwenden, den Kopierkonstruktor in Ihrer Klasse zu deklarieren, ihn aber nicht wirklich implementieren? Das sollte den Compiler freuen, solange er den Kopierctor nicht wirklich aufruft. Ich habe das nicht getestet, aber ich glaube, es sollte für Ihren Fall funktionieren, bis C ++ 17 eintrifft.

  • Ja – der tatsächlich implementierte Kopierkonstruktor hat eine schwerwiegende Ausnahme ausgelöst.

    – Peterh

    23. November 2018 um 22:15 Uhr

1645821610 144 Wie erzwinge ich das Entfernen von Kopien warum funktioniert es
Behutsamer Hahn

Sie können das Entfernen von Kopien (noch) nicht erzwingen (siehe andere Antworten).

Sie können jedoch einen Standard-Verschiebekonstruktor für Ihre Klasse bereitstellen, der den Rückgabewert verschiebt (und somit nicht kopiert), wenn RVO/NRVO nicht möglich ist. Dazu sollten Sie hinzufügen = default für Ihre Umzugsbauer:

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

Beispiel

  • @peterh Wahrscheinlich, weil es die Frage, die Sie gestellt haben, nicht beantwortet.

    – Juanchopanza

    6. Juli 2016 um 13:17 Uhr

  • @juanchopanza Es ist möglich, aber es ist mir nicht klar, warum. Was in dieser Antwort nicht klar ist, warum würden die Bewegungskonstruktoren benötigt.

    – Peterh

    6. Juli 2016 um 13:19 Uhr


  • @juanchopanza Es beantwortet die Frage, wenn auch aufgrund des Fehlens einer Erklärung schlecht. Dies ist eine gültige Methode, um sicherzustellen, dass die Klasse niemals kopiert wird, während die OPs weiterhin zugelassen werden return Aussage zu arbeiten.

    Benutzer743382

    6. Juli 2016 um 13:20 Uhr

  • @peterh In der Praxis findet keine Verschiebung statt, aber semantisch muss es eine Kopie oder eine Verschiebung geben, da C++ nach Wert zurückgibt. In C++98 bedeutet das, dass immer ein Kopierkonstruktor benötigt wird. In C++11 können Sie es durch einen Bewegungskonstruktor ersetzen. In C++17 wird in bestimmten Fällen beides nicht benötigt

    – KABoissonneault

    6. Juli 2016 um 13:22 Uhr

  • @juanchopanza Die dritte Frage ist das implizite “Wie mache ich das?” nach “Ich möchte garantieren, dass es niemals kopiert wird” 🙂

    Benutzer743382

    6. Juli 2016 um 13:22 Uhr

1645821610 669 Wie erzwinge ich das Entfernen von Kopien warum funktioniert es
Juanchopanza

Rückgabewertoptimierung (RVO und NRVO) bedeutet nicht, dass die Anforderung, dass die beteiligten Typen kopierbar oder verschiebbar sind, entfällt. Diese Anforderung gilt unabhängig davon, ob Sie RVO erhalten oder nicht.

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

In C++17 wird RVO unter bestimmten Umständen erzwungen, und die Anforderungen an Kopierbarkeit und Verschiebbarkeit fallen weg.

856760cookie-checkWie erzwinge ich das Entfernen von Kopien, warum funktioniert es nicht mit dem gelöschten Kopierkonstruktor?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy