2009-04-01 9 views
3

In einer Antwort auf Is it safe to store objects of a class which has an std::auto_ptr as its member variable in std::vector? habe ich festgestellt, dass eine Klasse, die ein auto_ptr enthielt, in einem Vektor gespeichert werden konnte, sofern die Klasse einen benutzerdefinierten Kopierkonstruktor hatte.Klasse mit auto_ptr in Vektor

Es gab mehrere Kommentare, die darauf hinwiesen, dass dies nicht der Fall war, daher ist diese Frage ein Versuch, das Problem zu klären. Betrachten Sie den folgenden Code ein:

#include <memory> 
#include <vector> 
using namespace std; 

struct Z {}; 

struct A { 

    A(Z z) 
     : p(new Z(z)) {} 

    A(const A & a) 
     : p(a.p.get() ? new Z(*a.p.get()) : 0) {} 

    // no assigment op or dtor defined by intent 

    auto_ptr <Z> p; 
}; 

int main() { 
    vector <A> av;    
    Z z;      
    A a(z); 
    av.push_back(a);  
    av.push_back(A(z)); 
    av.clear();    
}       

Bitte prüfen die oben & in Ihrer Antwort an, wo nicht definieren Verhalten im Sinne des C++ Standard für diese besondere Klasse in dieser besonderen Art und Weise verwendet, auftreten könnten. Ich bin nicht interessiert, ob die Klasse nützlich, gut erzogen, sortierbar ist oder wie sie unter Ausnahmen funktioniert.

Bitte beachten Sie auch, dass dies keine Frage über die Gültigkeit der Erstellung eines Vektors von auto_ptrs ist - ich bin mir der Probleme darüber bewusst.

Dank allen für Ihre Eingaben auf das, was in Nachhinein ist wahrscheinlich eine ziemlich dumme Frage. Ich glaube, ich konzentrierte mich zu viel auf die Kopie ctor & vergaß über Zuordnung. Der glückliche Gewinner meiner Akzeptanzstellen (und Punkte bedeuten Preise!) Ist litb für eine typisch erschöpfende Erklärung (sorry Earwicker)

+0

Ist dies ein 1. April Frage? AFAIK, du bist fähiger als die meisten von uns, um UB herauszufinden :-) – dirkgently

+0

Ich wusste, dass jemand das fragen würde :-) Aber nein, ich meine es ernst. –

Antwort

3

Der Versuch, die Liste der Orte zusammenzusetzen, macht das Beispiel undefiniert Verhalten.

#include <memory> 
#include <vector> 
using namespace std; 

struct Z {}; 

struct A { 

    A(Z z) 
     : p(new Z(z)) {} 

    A(const A & a) 
     : p(a.p.get() ? new Z(*a.p.get()) : 0) {} 

    // no assigment op or dtor defined by intent 

    auto_ptr <Z> p; 
}; 

int main() { 
    vector <A> av; 
    ... 
} 

Ich werde die Linien bis zu dem einen untersuchen, wo Sie den Vektor mit Ihrer Art A instanziiert. Der Standard hat sagen

In 23.1/3:

Die Art der Objekte in diesen Komponenten gespeichert sind, müssen die Anforderungen der CopyConstructible Typen (20.1.3) und die zusätzlichen Anforderungen der zuweisbaren Typen erfüllen.

In 23.1/4 (Hervorhebung von mir):

In Tabelle 64 ist, T der Typ verwendet wird, den Behälter zu instanziieren, ist t ein Wert von T und U ist ein Wert von (möglicherweise const) T.

+-----------+---------------+---------------------+ 
|expression |return type |postcondition  | 
+-----------+---------------+---------------------+ 
|t = u  |T&    |t is equivalent to u | 
+-----------+---------------+---------------------+ 

Tabelle 64

In 12.8/10:

Wenn die Klassendefinition einen Kopierzuweisungsoperator nicht explizit deklariert, wird einer implizit deklariert.Die implizit deklarierte Kopie Zuweisungsoperator für eine Klasse X wird die Form haben

X& X::operator=(const X&) 

wenn

  • jede direkte Basisklasse B von X hat eine Kopie Zuweisungsoperator, dessen Parameter des Typs const B &, const volatile B & oder B und
  • für alle nichtstatischen Datenelemente von X, die von einem Klassentyp M (oder einem Array davon) sind, hat jeder dieser Klassentypen einen Kopierzuweisungsoperator, dessen Parameter vom Typ const M & ist , c onst flüchtig M & oder M.

Andernfalls wird der implizit deklarierte Kopie Zuweisungsoperator wird die Form

X& X::operator=(X&) 

(Beachten Sie den letzten und vorletzter Satz)

In 17.4.3.6/1 and /2:

In bestimmten Fällen (Ersatzfunktionen, h andler-Funktionen, Operationen für Typen, die zur Instantiierung von Standardbibliotheksvorlagenkomponenten verwendet werden), hängt die C++ - Standardbibliothek von Komponenten ab, die von einem C++ - Programm bereitgestellt werden. Wenn diese Komponenten nicht ihren Anforderungen entsprechen, stellt der Standard keine Anforderungen an die Implementierung.

Insbesondere werden die Effekte in den folgenden Fällen nicht definiert:

  • für Typen als Vorlage Argument verwendet, wenn eine Vorlage Komponente instanziiert wird, wenn die Vorgänge von der Art nicht implementieren die Semantik der geltenden Anforderung Subklausel (20.1.5, 23.1, 24.1, 26.1). Operationen mit solchen Typen können einen Fehler melden, indem sie eine Ausnahme auslösen, sofern nicht anders angegeben.

Nun, wenn Sie bei der Spezifikation von auto_ptr aussehen beachten Sie eine Kopie-Zuweisungsoperator hat, die eine nicht-const auto_ptr nimmt. Daher wird der implizit deklarierte Kopierzuweisungsoperator Ihrer Klasse auch einen nicht-konstanten Typ als Parameter annehmen. Wenn Sie die oben genannten Orte sorgfältig lesen, werden Sie sehen, wie es besagt, dass das Instanziieren eines Vektors mit Ihrem Typ wie beschrieben ein undefiniertes Verhalten ist.

+0

Aber meine Klasse hat einen _explicitly_ deklarierten Kopierkonstruktor, also sehe ich nicht, wie dies zutrifft. –

+0

es gilt überhaupt nicht. Es fehlt der Kopierzuweisungsoperator - nicht der Kopierkonstruktor. Ich würde sagen, wie definiert, ist Ihre Kopie Konstruktor alles in Ordnung. –

+0

oops - meine falsch gelesen - sorry –

0

Seit der regulären auto_ptr semantischen könnte schlägt vor, dass das Eigentum während geben das Kopieren würde ich lieber hier verwenden boost::scoped_ptr. Natürlich fehlt der Zuweisungsoperator.

3

Ich denke nicht, dass es unbedingt der Fall ist, dass der obige Code sogar kompilieren wird. Sicherlich steht es dem Implementierer von std::vector frei, einen Zuweisungsoperator zu verlangen, von const A&?

Und mit gerade versuchte es, es nicht auf Visual Studio C++ 2008 Service Pack 1 nicht kompiliert:

binär '=': kein Betreiber gefunden, die nimmt einen rechten Operanden vom Typ ' const A‘(oder gibt es keine akzeptable Umwandlung)

Meine Vermutung ist, dass auf der Leitung von Herb Sutter, die Containerklassen in VC++ alle Anstrengungen, um die Standardanforderungen an ihren Typparametern zu verhängen, die speziell auf macht es schwierig,zu verwendenmit ihnen. Sie haben vielleicht die vom Standard gesetzten Grenzen überschritten, aber ich glaube mich daran zu erinnern, dass sie sowohl eine wahre Zuordnung als auch eine echte Kopienkonstruktion erfordert.

Es kompiliert jedoch in g ++ 3.4.5.

+0

Ja, jetzt erinnerst du mich daran Ich erinnere mich auch daran - ich denke, das beantwortet meine Frage :-( –

+0

Nun, wo ist mein grünes Häkchen für einen schlauen Jungen? :) –

+0

Alle guten Dinge kommen zu denen, die warten. –

0

Was ist mit den folgenden?

cout << av[ 0 ] << endl; 

Auch konzeptionell sollte eine Kopie den Artikel unverändert beibehalten. Dies wird in Ihrer Implementierung verletzt.

(Es ist eine ganz andere Sache, die Ihren ursprünglichen Code mit g++ -pedantic ... und Comeau fein kompiliert aber nicht VS2005.)

+0

"Auch konzeptionell sollte eine Kopie das Element von unverändert kopiert werden." - versuch das zu auto_ptr zu sagen! –

+0

Meine Frage war nicht über die Nützlichkeit der Klasse - offensichtlich ist es komplett kaputt, aber nur über UB. Aber wie Earwicker darauf hingewiesen hat, denke ich, dass VC++ für einmal richtig sein könnte.Interessant über Comeau obwohl ... –

+0

@Earwicker: Das war mein Punkt über auto_ptrs. – dirkgently

4

Objekte in Containern gelagert sind erforderlich „CopyConstructable“ sowie „Assignable“ (C++ sein 2008 23.1/3).

Ihre Klasse versucht, mit der CopyConstructable-Anforderung fertig zu werden (obwohl ich argumentiere, dass sie es immer noch nicht erfüllt - ich habe dieses Argument bearbeitet, da es nicht erforderlich ist und weil es strittig ist), aber es geht nicht um mit der Zuweisbaren Anforderung. Um zuweisbare (C++ 2008 23,1/4), muss Folgendes erfüllt sein, wo t ein Wert von T und u ist ein Wert von (möglicherweise const) T:

t = u gibt ein T& und t ist äquivalent zu u

Die Norm sagt auch in einer Notiz (20.4.5/3): "auto_ptr erfüllt nicht die CopyConstructible und zuweisbare Anforderungen für Standard Library Containerelemente und damit eine Standardbibliothek Behälter mit einer 01.231.337 Instanziierenführt zu undefiniertem Verhalten. "

Da Sie erklären oder definieren einen Zuweisungsoperator, eine implizite vorgesehen sein, nicht, dass die auto_ptr ‚s Zuweisungsoperator verwendet, die auf jeden Fall macht t nicht gleichwertig u, nicht zu erwähnen, dass es nicht funktionieren wird alles für "const T u" -Werte (was Earwicker's answer herausstellt - ich zeige nur die genauen Teile des Standards).

Verwandte Themen