Ich versuche, ein Array an eine Funktion übergeben und zu verhindern, schreiben "std :: unique_ptr" jedes Mal und um Inline-Konstruktion möglich machen, führe ich eine Typedef (ItemList), um das Array zu aliasieren.C++ 11 Liste Initialisierung seltsames Verhalten auf Visual Studio 2013
#include <iostream>
#include <memory>
class Base {
public:
Base()
{
std::cout << "Base ctor" << std::endl;
};
virtual ~Base()
{
std::cout << "Base dtor" << std::endl;
};
};
typedef std::unique_ptr<Base> ItemList[];
template<typename T>
class Derived : public Base {
T val;
public:
Derived(T i)
{
val = i;
std::cout << "Derived ctor" << val << std::endl;
};
~Derived()
{
std::cout << "Derived dtor" << val << std::endl;
};
};
void dummyFunc(ItemList)
{
}
void testFunc()
{
dummyFunc(ItemList{
std::make_unique<Derived<int>>(2),
std::make_unique<Derived<float>>(3.0f)
});
}
//Entry point
int main()
{
testFunc();
return 0;
}
Dies funktioniert wie geplant in einem Debug-Build und druckt;
Base ctor
Derived ctor2
Base ctor
Derived ctor2
Derived dtor2
Base dtor
Derived dtor2
Base dtor
So weit so gut. Aber wenn ich das im Release-Modus (mit allen nativen Compilern) erstelle, bekomme ich;
Base ctor
Derived ctor2
Base ctor
Derived ctor3
Derived dtor2
Base dtor
Das zweite Element im Array wird beim Verlassen des Lebenszyklus des Arrays nicht zerstört. Der einzige Weg, um es wie erwartet funktionieren zu lassen, ist die Verwendung eines C++ 03 Stils Initialisierung oder Debug-Modus;
ItemList tmpList = {
std::make_unique<Derived<int>>(2),
std::make_unique<Derived<float>>(2.0f)
};
dummyFunc(tmpList);
Dies führt zu dem beabsichtigten Verhalten (alle Destruktoren genannt).
Ich habe dies noch nicht mit einem anderen Compiler getestet, aber ist das das erwartete Verhalten? Was mache ich falsch oder verpasse ich etwas?
Update:
Interessanter dtors genannt werden, wie mit Basis Instanzen erwartet;
dummyFunc(ItemList{
std::make_unique<Base>(),
std::make_unique<Base>()
});
Ausgänge;
Und nur die Initialisierung des Arrays (ohne Funktionsaufruf) verhält sich genauso wie mit dem Funktionsaufruf.
Interessant ... Es kompiliert sowohl auf Win-und Mac-Standard-Compiler. Nicht sicher über das Release-Verhalten auf dem Mac, wird aber prüfen. Havent hat deine Lösung schon probiert. Auf der anderen Seite bin ich mir nicht sicher, ob es sich wirklich beschweren sollte, ein temporäres Array zu verwenden. Es ist mein Problem, eine Warnung wäre ein besseres Verhalten. Sollte der Standard für dieses Verhalten überprüfen. –
@AliNaciErdem die Adresse eines Rvalue zu nehmen ist illegal, siehe Standard: 'Das Ergebnis des unary & operator ist ein Zeiger auf seinen Operanden. Der Operand soll ein Lvalue oder eine qualifizierte ID sein. Über das Verhalten von VS in Release habe ich meine Antwort aktualisiert. – AntiClimacus
Dies erklärt noch nicht das Verhalten. Wenn es in einen Zeiger auf das erste Element umgewandelt wird, warum wird dann das erste Element zerstört? Ich verstehe es nicht. Es ist in Ordnung, wenn das Objekt zerstört wird, bevor es an die Funktion übergeben wird, aber es sollte zerstört werden, da es auf dem Stapel zugewiesen ist. –