std :: Tupel für nicht kopierbare und nicht bewegliche Objekte

8

Ich habe eine Klasse mit copy & amp; move ctor gelöscht.

%Vor%

Und ich möchte ein Tupel mit Objekten dieser Klasse erstellen. Aber Folgendes kompiliert nicht:

%Vor%

Auf der anderen Seite kompiliert das folgende , gibt aber eine überraschende Ausgabe.

%Vor%

Ausgabe

%Vor%

Dies bedeutet, dass dtor für Objekte aufgerufen wird, sobald die Tupelkonstruktionslinie endet. Also, was ist die Bedeutung eines Tupels von zerstörten Objekten?

    
gjha 24.09.2015, 13:47
quelle

2 Antworten

10

Das ist schlecht:

%Vor%

Sie erstellen tuple of rvalue-Referenzen auf Provisorien, die am Ende des Ausdrucks zerstört werden, sodass Ihnen nicht mehr benötigte Referenzen zur Verfügung stehen.

Die korrekte Aussage wäre:

%Vor%

Bis vor kurzem wurde das oben Genannte jedoch vom Standard nicht unterstützt. In N4296 lautet die Formulierung um den relevanten Konstruktor für tuple [tuple.cnstr]:

%Vor%      

Benötigt : sizeof...(Types) == sizeof...(UTypes) . is_constructible<Ti, Ui&&>::value ist wahr   für alle i .
Effekte : Initialisiert die Elemente im Tupel mit dem entsprechenden Wert in std::forward<UTypes>(u) .
Anmerkung : Dieser Konstruktor soll nicht teilnehmen in Überladungsauflösung wenn nicht jeder Typ in UTypes ist   implizit in den entsprechenden Typ in Types umwandelbar.

Dieser Konstruktor war also nicht an der Überladungsauflösung beteiligt, weil int nicht implizit in A konvertiert werden kann. Dies wurde durch die Übernahme von Verbesserung von pair und tuple behoben. , die genau Ihren Anwendungsfall adressiert:

%Vor%

Die neue Formulierung für diesen Konstruktor lautet ab N4527:

  

Hinweise : Dieser Konstruktor darf nicht an der Überladungsauflösung teilnehmen, wenn sizeof...(Types) >= 1 und is_constructible<Ti, Ui&&>::value für alle i wahr ist. Der Konstruktor ist genau dann explizit   wenn is_convertible<Ui&&, Ti>::value false für mindestens ein i ist.

Und is_constructible<A, int&&>::value ist wahr.

Um den Unterschied auf andere Weise darzustellen, hier eine extrem abgespeckte Tupel-Implementierung:

%Vor%

Wenn USE_OLD_RULES definiert ist, ist der erste Konstruktor der einzige ausführbare Konstruktor und daher wird der Code nicht kompiliert, da D nicht kopierbar ist. Andernfalls ist der zweite Konstruktor der beste mögliche Kandidat und dieser ist wohlgeformt.

Die Einführung war so aktuell, dass weder gcc 5.2 noch clang 3.6 dieses Beispiel noch kompilieren werden. Sie benötigen also entweder einen neueren Compiler (gcc 6.0 funktioniert) oder ein anderes Design.

    
Barry 24.09.2015, 14:20
quelle
1

Ihr Problem ist, dass Sie explizit nach einem Tupel von rvalue-Referenzen gefragt haben, und eine rvalue-Referenz ist nicht weit von einem Zeiger entfernt.

So erstellt auto q = std::tuple<A&&,A&&>(A{100},A{200}); zwei A-Objekte, nimmt (rvalue) Referenzen auf sie, erstellt das Tupel mit den Referenzen ... und zerstört die temporären Objekte, so dass Sie zwei freie Referenzen erhalten.

Selbst wenn es gesagt wird, dass es sicherer ist als das gute alte C und seine ungeeigneten Zeiger, erlaubt C ++ Programmierern immer noch, falsche Programme zu schreiben.

Wie auch immer, das Folgende wäre sinnvoll (beachten Sie die Verwendung von A & amp; und nicht A & amp; & amp;;):

%Vor%     
Serge Ballesta 24.09.2015 14:22
quelle

Tags und Links