Deklaration mit new
-
int i = 3; int i(3);Ist auch das gleiche.
-
Naja, so ganz das gleiche ist es wohl nicht. Sonst
ware diesstd::auto_ptr<MyClass> p(new MyClass);ja da gleiche wie dies
std::auto_ptr<MyClass> p = new MyClass;Letzteres ist aber nicht möglich, da der Konstruktor von std::auto_ptr<> ja
'explicit' ist.
-
Strolch schrieb:
int i = 3; int i(3);Ist auch das gleiche.
Danke, das hatte ich mir schon gedacht.
Was aber ist dann aber folgendes:
new MeineKlasse();was ich auch schonmal gesehen habe.
-
bladerunner10 schrieb:
Naja, so ganz das gleiche ist es wohl nicht. Sonst
ware diesstd::auto_ptr<MyClass> p(new MyClass);ja da gleiche wie dies
std::auto_ptr<MyClass> p = new MyClass;Letzteres ist aber nicht möglich, da der Konstruktor von std::auto_ptr<> ja
'explicit' ist.std::auto_ptr<MyClass> p = new MyClass;entspricht:
std::auto_ptr<MyClass> p( std::auto_ptr_ref<MyClass>( new MyClass ) );
-
David_pb schrieb:
std::auto_ptr<MyClass> p = new MyClass;entspricht:
std::auto_ptr<MyClass> p( std::auto_ptr_ref<MyClass>( new MyClass ) );Nö.
std::auto_ptr<MyClass> p = new MyClass;ist nicht möglich!
VC2008 schrieb:
ap.cc(7) : error C2440: 'Initialisierung': 'MyClass *' kann nicht in 'std::auto_ptr<_Ty>' konvertiert werden
with
[
_Ty=MyClass
]
Konstruktor für class 'std::auto_ptr<_Ty>' ist als 'explicit' deklariert
with
[
_Ty=MyClass
]
-
Wenn ein Type T implizit in auto_ptr_ref konvertiert werden kann, sollte es eigentlich gehen.
-
David_pb schrieb:
Wenn ein Type T implizit in auto_ptr_ref konvertiert werden kann, sollte es eigentlich gehen.
Na dann zeig mal, wie das gehen soll.
-
Hm, kann auch sein, dass das in dem Fall einfach Unkonformität von Visual Studio ist. Folgender Code wird bei mir z.B. kompiliert (VC++ 2005):
struct foo { foo( int x ) {} }; struct bar { explicit bar( int x ) { }; bar( foo c ) { } }; int main() { bar b = 10; }Wie ich das auf die Schnelle aus dem Standard rauslesen konnt ist das aber wohl nicht konform. Nunja...
Auf jeden Fall wird bei einem T a = b; immer versucht einen entsprechenden Konstruktor zu verwenden (nicht etwa den Zuweissungsoperator).
-
David_pb schrieb:
Auf jeden Fall wird bei einem T a = b; immer versucht einen entsprechenden Konstruktor zu verwenden (nicht etwa den Zuweissungsoperator).
Das ist richtig. Dennoch muss bei dieser Art der Initialisierung die Zuweisung möglich sein (sprich der Ausdruck "a = b" ohne Initialisierung muss ebenfalls zulässig sein). Erst dann ist die Initialisierung auch zulässig.
Der MSVC2005 setzt das meines Wissens in der Tat falsch um.
EDIT:
Zum auto_ptr_ref - über diese Klasse wird im Standard so wenig angegeben, dass Experimente damit bestenfalls rein spekulativ sind
-
LordJaxom schrieb:
Das ist richtig. Dennoch muss bei dieser Art der Initialisierung die Zuweisung möglich sein (sprich der Ausdruck "a = b" ohne Initialisierung muss ebenfalls zulässig sein). Erst dann ist die Initialisierung auch zulässig.
Der MSVC2005 setzt das meines Wissens in der Tat falsch um.
Der MSVC2008 ist an der Stelle ebenfalls buggy.
-
LordJaxom schrieb:
Zum auto_ptr_ref - über diese Klasse wird im Standard so wenig angegeben, dass Experimente damit bestenfalls rein spekulativ sind

Ja, die Infos darüber sind in der Tat sehr rar!

-
Der auto_ptr ist in C++0x eh deprecated. Nicht ohne Grund!

-
bladerunner10 schrieb:
Naja, so ganz das gleiche ist es wohl nicht. Sonst
ware diesstd::auto_ptr<MyClass> p(new MyClass);ja da gleiche wie dies
std::auto_ptr<MyClass> p = new MyClass;Letzteres ist aber nicht möglich, da der Konstruktor von std::auto_ptr<> ja
'explicit' ist.Kannst du bitte erklären wo da der Zusammenhang zum diskutierten Thema besteht. Wenn man das überfliegt, sieht es irgendwie nach sinnlosem Murks aus, besonders die 2. Codezeile.
-
bladerunner10 schrieb:
Naja, so ganz das gleiche ist es wohl nicht. Sonst
ware diesstd::auto_ptr<MyClass> p(new MyClass);ja da gleiche wie dies
std::auto_ptr<MyClass> p = new MyClass;Letzteres ist aber nicht möglich, da der Konstruktor von std::auto_ptr<> ja
'explicit' ist.auto_ptr ist eine Klasse, int ist ein Skalar. Und dies ist einer der Stellen, an denen dieser Unterschied nicht egal ist.
int i = 3; int i(3);Beide Varianten sind semantisch absolut identisch (Letzteres ist nur furchtbar weil unleserlich... man kann mit der Vereinheitlichung auch übertreiben; an vielen Stellen habe ich echte Schwierigkeiten, dies auf Anhieb von Funktionsdeklarationen zu unterscheiden. Und eine Schreibweise, die dazu führt, dass ich das Ganze eine ganze Sekunde länger betrachten muss, ist schlecht, denn das ist zu lange, wenn man Code nur überfliegen will).
bladerunner10 schrieb:
Naja, so ganz das gleiche ist es wohl nicht. Sonst
ware diesstd::auto_ptr<MyClass> p(new MyClass);ja da gleiche wie dies
std::auto_ptr<MyClass> p = new MyClass;Letzteres ist aber nicht möglich, da der Konstruktor von std::auto_ptr<> ja
'explicit' ist.Das erste ist direkte Initialisierung, das zweite Copy-Initialisierung. Und letzteres ist mit auto_ptr eben nicht möglich (gewollt, denn man will ja nicht versehentlich Zeiger in auto_ptr stecken; das sollte immer ganz bewusst erfolgen). Das ist auch nichts besonderes, für jeden anderen vernünftigen Smartpointer gilt dies ganz genauso.
Strolch schrieb:
Der auto_ptr ist in C++0x eh deprecated. Nicht ohne Grund!

Natürlich erfolgt so etwas nicht ohne Grund, der wurde aber hier gar nicht genannt.
Der Standard sagt nicht viel zu auto_ptr_ref aus mehreren Gründen: einerseits handelt es sich im Prinzip um ein Implementationsdetail; andererseits hat es offensichtlich auch im Standardkomitee lange gedauert, bis die Funktionsweise von auto_ptr wirklich verstanden wurde. Fakt ist schließlich auch, das keiner der großen Compiler (die ich daraufhin mal unter die Lupe genommen habe: msvc, bcb, g++ jeweils in verschiedenen Versionen), auto_ptr tatsächlich korrekt und sicher umsetzt - die Fehler variieren allerdings zwischen den Compilern und Versionen. Umgekehrt sollte das allerdings nicht zu dem Trugschluss verleiten, auto_ptr wäre etwas gefährliches und besser zu vermeiden - dem ist trotz dieser Bugs im Allgemeinen nicht so: für die Zwecke, für die auto_ptr primär gedacht ist, gibt es gegenwärtig keine bessere Alternative. Es ist aber eben auch kein Smartpointer für alles, wie etwa shared_ptr, den man im Allgemeinen ohne Bedenken einsetzen kann (wenn man ggf. eine gewisse Ineffizienz in Kauf nimmt).
-
camper schrieb:
Das erste ist direkte Initialisierung, das zweite Copy-Initialisierung. Und letzteres ist mit auto_ptr eben nicht möglich (gewollt, denn man will ja nicht versehentlich Zeiger in auto_ptr stecken; das sollte immer ganz bewusst erfolgen). Das ist auch nichts besonderes, für jeden anderen vernünftigen Smartpointer gilt dies ganz genauso.
Das zweite soll eine Copy-Initialisierung sein? Eine Copy-Initialisierung geht auch bei auto_ptr. Man kann nur eben kein auto_ptr-Objekt mit irgendeinem Objekt eines anderen Typs initialisieren. Da der Konstruktor als explicit deklariert ist gibt es keine Standardumwandlung, daher ist die die zweite Codezeile einfach ein Fehler.
Das wäre z.B. auch bei
int i = 3.3;oder
std::string s = "Hallo!";oder jeder beliebigen anderen Klasse der Fall, wenn es keine entsprechende Standardumwandlung in das benötigte Format gäbe.
-
Kritiker schrieb:
camper schrieb:
Das erste ist direkte Initialisierung, das zweite Copy-Initialisierung. Und letzteres ist mit auto_ptr eben nicht möglich (gewollt, denn man will ja nicht versehentlich Zeiger in auto_ptr stecken; das sollte immer ganz bewusst erfolgen). Das ist auch nichts besonderes, für jeden anderen vernünftigen Smartpointer gilt dies ganz genauso.
Das zweite soll eine Copy-Initialisierung sein? Eine Copy-Initialisierung geht auch bei auto_ptr. Man kann nur eben kein auto_ptr-Objekt mit irgendeinem Objekt eines anderen Typs initialisieren.
Schön, dass einer aufpasst. Ich hätte schreiben sollen: /* Edit: etwas anderes, hab grad keine Lust, über die genaue Formulierung nachzudenken */.
Edit 2: Deine Formulierung ist ja auch nicht ganz korrekt. Man kann ja auto_ptr implizit aus anderen (verwandten) auto_ptr (unter bestimmten Umständen) initialisieren.struct B {}; struct D : B {}; auto_ptr<D> p(new D); auto_ptr<B> q = p; // okEntscheidend für die Korrektheit beider Formulierung ist, dass wir genauer spezifizieren, um welche Quelltypen es gehen soll.
Die genaue Sprachregelung ist ohnehin insignifikant, wenn das Prinzip verstanden wurde. In problematischen Fällen kann es nützlich sein, verschiedene äquivalente Formulierungen zu kennen. Um etwa zu erklären warum in
struct B {}; struct D : B {}; auto_ptr<D> D_src(); auto_ptr<B> p1(D_src()); //(1) auto_ptr<D> p1=D_src(); //(2)(1), aber nicht (2) möglich ist. Es existiert ja keine Konvertierungssequenz von rvalue-auto_ptr<D> in lvalue-auto_ptr<B>. Das ist im Grunde der einzige prinzipiell (wenn wir nicht Compiler-Magie unterstellen wollen) unheilbare Fehler im auto_ptr-Design.
Kritiker schrieb:
Da der Konstruktor als explicit deklariert ist gibt es keine Standardumwandlung, daher ist die die zweite Codezeile einfach ein Fehler.
Wenn wir ganz genau sein wollen, muss es implizite Umwandlung heißen (die dann nicht möglich ist). Eine Standardumwandlung beinhaltet ohnehin nie den Aufruf eines Konstruktors oder Umwandlungsoperators.
Das wäre z.B. auch bei
int i = 3.3;oder
std::string s = "Hallo!";oder jeder beliebigen anderen Klasse der Fall, wenn es keine entsprechende Standardumwandlung in das benötigte Format gäbe.
Ganz recht (implizite Umwandlung im zweiten Fall).
-
Natürlich, es heißt "implizite Umwandlung". War "etwas" schlampig von mir.

Stecke jetzt nicht so tief im Thema drin, aber bist du dir sicher, dass der Fall (2) in deinem Beispiel nicht funktioniert? Sieht eigentlich plausibel aus.
-
Kritiker schrieb:
Natürlich, es heißt "implizite Umwandlung". War "etwas" schlampig von mir.

Stecke jetzt nicht so tief im Thema drin, aber bist du dir sicher, dass der Fall (2) in deinem Beispiel nicht funktioniert? Sieht eigentlich plausibel aus.
Plausibel sieht es aus, und es wäre schön, wenn es funktionierte (um nackte Zeiger besser zu imitieren).
struct B {}; struct D : B {}; auto_ptr<B> B_src(); auto_ptr<D> D_src(); auto_ptr<B> p(B_src()); //(1) ok, direkte Initialisierung auto_ptr<B> q(D_src()); //(2) ok, direkte Initialisierung auto_ptr<B> r=B_src(); //(3) ok, Copy-Initialisierung vom gleichen Typ auto_ptr<B> s=D_src(); //(4) Fehler, Copy-Initialisierung von nicht verwandtem Typ, bräuchte Konvertierungssequenz mit 2 Konvertierungsfunktionen(1) ist Problemlos: es werden alle Konstruktoren untersucht, und nur
auto_ptr<B>::auto_ptr(auto_ptr_ref<B>) kommt in Frage: dazu muss der initialisierende Ausdruck in ein auto_ptr_ref<B> konvertiert werden, wozu der entsprechende Konvertierungsoperator auto_ptr<B>::operator auto_ptr_ref<B> benutzt wird.
(2) ist ebenso Problemlos, der gleiche Konstruktor wird benutzt, nur der aufgerufene Konvertierungsoperator ist hier auto_ptr<D>::operator auto_ptr_ref<B>
(3) ist analog zu (1) weil der initialisierende Ausdruck vom gleichen Typ ist (cv-Qualifizierung ist egal und auch ein abgeleiteter Typ des Zieltyps fiele unter diese Regel)
(4) wird anders behandelt: hier muss der initialisierende Ausdruck in auto_ptr<B> konvertiert werden, aber ein temporäres Objekt (bzw. rvalue) entsteht nur durch Konstruktoraufruf (d.h. Konvertierungsoperatoren werden nur berücksichtigt, wenn sie in cv Base& bzw. cv Derived& konvertieren - deshalb ist der Konvertierungsoperator auto_ptr<T>::operator auto_ptr<U> nutzlos und wird niemals aufgerufen). Das ist anders als die anderen Fälle, dort war der Zieltyp der Konvertierung jeweils auto_ptr_ref<B> und das temporäre Objekt entstand durch eine Operatorfunktion. Hier bräuchten wir nun 2 Funktionsaufrufe für die Konvertierung (erst den Konvertierungsoperator auto_ptr_ref, dann den Konstruktor) und das ist unzulässig. All die anderen Konstruktoren kommen nicht in Frage, weil die nur mit modifizierbaren Referenzen arbeiten und demzufolge nicht an das rvalue-Argument binden können.
-
OK, jetzt weiß ich was du meinst. War nur leicht verwirrt, weil der Quelltext in deinem Beitrag so aussah:
camper schrieb:
struct B {}; struct D : B {}; auto_ptr<D> D_src(); auto_ptr<B> p1(D_src()); //(1) auto_ptr<D> p1=D_src(); //(2)Du meintest hier wohl im Fall (2) auto_ptr<B>.
camper schrieb:
Edit 2: Deine Formulierung ist ja auch nicht ganz korrekt. Man kann ja auto_ptr implizit aus anderen (verwandten) auto_ptr (unter bestimmten Umständen) initialisieren.
struct B {}; struct D : B {}; auto_ptr<D> p(new D); auto_ptr<B> q = p; // okDa bin ich mir auch nicht sicher ob das OK ist. Es entspricht ja mehr oder weniger deinem Fall (2).
Noch verwirrender ist, dass z.B. MVSC++ auch die Variante (2) "schluckt" und korrekt ausführt. Während z.B. MinGW genau den von dir angedeuteten Fehler aufzeigt (no matching function call for ... ).
Hab kurz jeweils die Headerdateien (memory) überflogen um Unterschiede zu erkennen, was mir nicht gelungen ist. Vielleicht hilft jemand aus, der das schon weiß?
-
Vermutlich wird das ganz von Mvc++ einfach falsch interpretiert.