Dies ist eine Folge von diese Frage
im folgenden Code, warum Zeile 1 kompiliert, während Zeile 2 und 3 nicht (mit Visual C ++ 2010)
%Vor%(Anmerkung: BA ist eine Kopie von boost :: nicht kopierbar)
bearbeiten: Mein Problem ist nicht zu wissen, warum Zeile 2 und 3 nicht kompilieren (ich weiß, dass der Kopierkonstruktor privat ist), aber warum Zeile 1 tut.
Der Compiler akzeptiert die erste Verwendung falsch. Selbst wenn die Kopie entfernt wird, muss der Kopierkonstruktor zugänglich sein, damit der Code korrekt ist.
In diesem speziellen Fall gibt es einen implizit deklarierten Kopierkonstruktor in A
:
§12.8 / 4 Wenn die Klassendefinition einen Kopierkonstruktor nicht explizit deklariert, wird einer implizit deklariert.
Das ist implizit definiert:
§12.8 / 7 Ein implizit deklarierter Kopierkonstruktor ist implizit definiert, wenn er verwendet wird, um ein Objekt seines Klassentyps aus einer Kopie eines Objekts seines Klassentyps oder eines von seinem Klassentyp abgeleiteten Klassentyps zu initialisieren108). [Anmerkung: Der Kopierkonstruktor ist implizit definiert, selbst wenn die Implementierung seine Verwendung weggelassen hat (12.2). ] Ein Programm ist schlecht gemacht , wenn die Klasse, für die ein Kopierkonstruktor implizit definiert ist,
hat- ein nicht statisches Datenelement vom Klassentyp (oder Array davon) mit einem nicht zugänglichen oder mehrdeutigen Kopierkonstruktor oder
- Eine Basisklasse mit einem nicht zugänglichen oder mehrdeutigen Kopierkonstruktor.
Tatsächlich sollte Zeile 1 nicht kompiliert werden.
Anscheinend hat vc ++ 2010 in diesem Fall Probleme beim Erzwingen von Sprachregeln (möglicherweise, weil sie mit einer Basisklasse und nicht mit dem Objekt selbst zusammenhängen).
g ++ Diagnosemeldung über Zeile 1 ist sehr klar
%Vor%Der Kopierkonstruktor wird als privat deklariert, so dass keine Kopie des Klassenobjekts mit diesem privaten Kopierkonstruktor erstellt werden kann, was zu einem Fehler führt.
%Vor% Verwendet A::A(const A&)
, um ein neues Objekt A
zu erstellen. A
wird von ABase
abgeleitet und ruft auf
ABase::ABase(const ABase&)
in seinem Konstruktor, der für ihn nicht selbst kompiliert wird.
Hier ist die Ausgabe von Ideone. Es kompiliert nicht einmal auf gcc.
Warum funktioniert es in Visual Studio?
Der Grund ist eine mögliche Rückgabewertoptimierung durch den visuellen C ++ - Compiler, der den Kopierkonstruktor elimiert.
Gemäß dem C ++ - Standard 12.8 Kopieren von Klassenobjekten Abschnitt 15
Wenn bestimmte Kriterien erfüllt sind, darf eine Implementierung die Kopierkonstruktion eines Klassenobjekts weglassen, selbst wenn der Kopierkonstruktor und / oder der Destruktor für das Objekt Nebeneffekte haben. In solchen Fällen behandelt die Implementierung die Quelle und das Ziel der ausgelassenen Kopieroperation als einfach zwei verschiedene Arten, auf dasselbe Objekt Bezug zu nehmen, und die Zerstörung dieses Objekts erfolgt zu einem späteren Zeitpunkt, wenn die beiden Objekte gewesen wären zerstört ohne die Optimierung.111)
Siehe meine Antwort hier welches den Standard und den Beispielcode diesbezüglich zitiert.
%Vor% Kompiliert nicht aus dem gleichen Grund, dass ABase::ABase(const ABase&)
privat ist.
Kompiliert nicht, da B( const B& );
privat ist.
Zeile 1 ist eine Rückgabewertoptimierung (der Compiler sieht, dass keine temporäre Variable für A()
erstellt werden muss und der Kopierkonstruktor / Zuweisungsoperator der Variablen a
zugewiesen wird). Dies kompiliert jedoch nicht auf GCC (Version 4.2.1) und sollte vermieden werden.
Zeile 2 wird nicht kompiliert, da der Compiler in diesem Fall keinen Zuweisungsoperator für Sie generiert. Zeile 3 kompiliert nicht wie erwartet.
Reagan Zusammenfassung: Zeile 1 funktioniert, weil es Microsoft ist, die anderen verhalten sich wie erwartet.
Warum kompiliert Zeile 1? Weil dein Compiler kaputt ist; es sollte nicht,
nach dem Standard. Während Ihre Klasse A
implizit hat
Erklärter Copy Constructor, §12.8 / 7 des Standards besagt, dass An
Implizit deklarierter Copy-Konstruktor wird implizit definiert, wenn dies der Fall ist
verwendet, um ein Objekt zu initialisieren (wie in A a = A();
), und dass ein Programm ist
schlecht gebildet (und somit eine Diagnose erforderlich), wenn der Konstruktor ist
implizit defiend und eine Basisklasse hat einen unzugänglichen oder mehrdeutigen
Konstruktor kopieren Es gibt sogar eine Notiz, dass dies der Fall ist, selbst wenn
Die Implementierung unterscheidet den Kopierkonstruktor. Du bist Compiler nicht
weit genug gehen: es sieht die implizit erklärte öffentliche Kopie
Konstruktor, aber es versucht nicht, es implizit zu definieren, obwohl die
Standard sagt eindeutig, dass es sollte.
Ich glaube, das liegt daran, dass der Konstruktor geschützt ist, nicht privat. Der vom Compiler bereitgestellte Konstruktor in Klasse A kann den geschützten Konstruktor der Klasse ABase frei aufrufen, also funktioniert es.
Außerdem ist Zeile 1 kein Kopierkonstruktor. Eine Deklaration mit einer Zuweisung ist ein Sonderfall, der in einen Konstruktor umgewandelt wird.