Frage

Aktualisieren:Das Codebeispiel wurde bearbeitet, um AutoA als Problemumgehung zu verwenden (was ursprünglich beabsichtigt war).Das wurde mir klar, nachdem ich die Antwort von rlbond gesehen hatte.

Ich versuche, die Verwendung von zu integrieren auto_ptr in meinem Code basierend auf Empfehlungen aus diesem Thread:

Drücken Sie die Verwendung von C++-Argumenten über Methodenschnittstellen aus

Beim Kompilieren mit Visual Studio 6.0 erhalte ich jedoch einige unerwartete Kompilierungsfehler.Es gibt ein Problem beim Umgang mit Aufgaben/Kopien von a std::auto_ptr eines abgeleiteten Typs zu a std::auto_ptr des Basistyps.Handelt es sich hierbei um ein spezifisches Problem meines Compilers?

Ich weiß, dass die Verwendung von Boost dringend empfohlen wird, aber für mein Projekt ist dies keine Option.Wenn ich es noch verwenden möchte auto_ptr, bin ich gezwungen, die Problemumgehung des Anrufs zu nutzen std::auto_ptr::release()?Nach allem, was ich bisher erlebt habe, führt dieses Problem zu einem Compilerfehler, sodass es leicht zu erkennen ist.Könnte mich die Übernahme der Konvention, „release“ aufzurufen, um sie einem „auto_ptr“ des Basistyps zuzuweisen, durchgehend Wartungsproblemen aussetzen?Vor allem, wenn es mit einem anderen Compiler erstellt wurde (vorausgesetzt, andere Compiler haben dieses Problem nicht).

Wenn die release() Die Problemumgehung ist aufgrund meiner Umstände nicht sinnvoll. Sollte ich auf eine andere Konvention zur Beschreibung der Eigentumsübertragung zurückgreifen?

Das folgende Beispiel veranschaulicht das Problem.

#include "stdafx.h"
#include <memory>

struct A
{
    int x;
};

struct B : public A
{
    int y;
};

typedef std::auto_ptr<A> AutoA;
typedef std::auto_ptr<B> AutoB;

void sink(AutoA a)
{
    //Some Code....
}

int main(int argc, char* argv[])
{
    //Raws to auto ptr
    AutoA a_raw_to_a_auto(new A());
    AutoB b_raw_to_b_auto(new B());
    AutoA b_raw_to_a_auto(new B());

    //autos to same type autos
    AutoA a_auto_to_a_auto(a_raw_to_a_auto);
    AutoB b_auto_to_b_auto(b_raw_to_b_auto);

    //raw derive to auto base
    AutoB b_auto(new B());

    //auto derive to auto base
    AutoA b_auto_to_a_auto(b_auto);  //fails to compile

    //workaround to avoid compile error.
    AutoB b_workaround(new B());
    AutoA b_auto_to_a_auto_workaround(b_workaround.release());

    sink(a_raw_to_a_auto);
    sink(b_raw_to_b_auto);  //fails to compile

    return 0;
}

Kompilierungsfehler:

Compiling...
Sandbox.cpp
C:\Program Files\Microsoft Visual Studio\MyProjects\Sandbox\Sandbox.cpp(40) : error C2664: '__thiscall std::auto_ptr<struct A>::std::auto_ptr<struct A>(struct A *)' : cannot convert parameter 1 from 'class std::auto_ptr<struct B>' to 'struct A *'
        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
C:\Program Files\Microsoft Visual Studio\MyProjects\Sandbox\Sandbox.cpp(47) : error C2664: 'sink' : cannot convert parameter 1 from 'class std::auto_ptr<struct B>' to 'class std::auto_ptr<struct A>'
        No constructor could take the source type, or constructor overload resolution was ambiguous
Error executing cl.exe.

Sandbox.exe - 2 error(s), 0 warning(s)
War es hilfreich?

Lösung

Der erste ist einfach:

AutoA b_auto_to_a_auto(b_auto);  //fails to compile

Dies schlägt auf VC6 fehl, da es erforderlich ist Member-Funktionsvorlagen, etwas, das die Standardbibliothek von VC6 nicht unterstützt.Es wird jedoch auf standardkonformen Compilern kompiliert.

Problemumgehung:

AutoA b_auto_to_a_auto( b_auto.release() );

Der zweite ist viel subtiler :)

sink(b_raw_to_b_auto);  //fails to compile

Dieser sollte nicht mit einem standardkonformen Compiler kompiliert werden, da eine implizite Konvertierung stattfindet.Der Compiler wandelt das Obige in um

sink( std::auto_ptr<A>( b_raw_to_b_auto ) );

Jedoch, sink dauert std::auto_ptr<A> von Wert, also das Provisorische std::auto_ptr<A> implizit vom Compiler erstellt werden muss kopierkonstruiert in das Argument zu sink.Nun, solche Provisorien sind es Werte.R-Werte binden nicht an nicht konstante Referenzen, aber std::auto_ptrDer „Kopierkonstruktor“ übernimmt sein Argument nicht-konst Referenz.

Da haben Sie es – Kompilierungsfehler.AFAICS das ist normkonformes Verhalten.C++-0x „Move Semantics“ wird das beheben, indem es einen „Kopierkonstruktor“ hinzufügt, der eine R-Wert-Referenz akzeptiert, obwohl ich nicht sicher bin, wie viel Liebe das bedeutet std::auto_ptr werde auch in Zukunft noch was mit bekommen std::shared_ptr und alles.

Problemumgehung für den zweiten:

AutoA tmp( b_raw_to_b_auto/*.release() for VC6*/ );
sink( tmp );

Andere Tipps

AutoA b_auto_to_a_auto(b_auto);  //fails to compile

sink(b_raw_to_b_auto);  //fails to compile

Pavel Minaev weist auf etwas hin, das ich eigentlich nicht wusste:

Der erste Anruf sollte kompilieren, da eine implizite Konvertierung von einem B* zu einem A* vorhanden ist. Die zweite wird jedoch nicht kompilieren. Das Folgende wird:

sink(static_cast<AutoA>(b_raw_to_b_auto));

VC6 ist berüchtigt, dass sie nicht sehr gut mit Vorlagen ist.

Ich empfehle Ihnen dringend, Ihre Codebasis auf eine zu aktualisieren, die tatsächlich funktioniert, und beginnt, Raii -Techniken zu verwenden, insbesondere auf boost::shared_ptr. Ich weiß, dass Sie sagen, dass Sie es nicht können, und ich weiß, dass es schwierig ist, aber Sie werden praktisch keine Speicherlecks und viele, viele Fehler haben.

Andererseits können Sie vielleicht auch ohne volle Funktionalität verwenden auto_ptr?

Hier gibt es zwei Probleme. Zunächst einmal:

AutoA b_auto_to_a_auto(b_auto);  

es ist perfekt Standard konform und sollte kompilieren. Lassen Sie mich erklären warum. ISO C ++-Standard gibt (20.4.5.1 [lib.auto.ptr.cons]/4-6) der folgende Konstruktor für auto_ptr<X> (unter anderen);

template<class Y> auto_ptr(auto_ptr<Y>&) throw();

Beachten Sie, dass Y ist ein anderer Typ als X hier. Und der Standard weiterhin sagt:

Benötigt: y* kann implizit in x* konvertiert werden.

Das einzige, worauf Sie hier achten müssen, ist, dass das Konstruktor-Argument eine Referenz zu Nicht-Konst ist. Für Ihren Fall ist dies kein Problem (da Sie dort eine nicht konstante Variable bestehen), wird es jedoch für den nächsten Teil wichtig. Zahlen Sie hier: Was Sie sehen, ist Nicht standardmäßiges Verhalten in VC6. Es sollte Kompilieren Sie auf einem konformen Compiler (und werden auf VC7 und höher kompilieren). Nun zur zweiten Sache:

sink(b_raw_to_b_auto);  //fails to compile

Dieser wird tatsächlich perfekt von Mmutz erklärt, also werde ich hier nicht auf Details eingehen - siehe seine Antwort. Zum Schluss darüber: Ja, diese Zeile sollte nicht kompilieren und nicht in einem konformen Compiler (oder VC6, wie Sie herausgefunden haben).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top