2016-11-05 4 views
0

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.

Antwort

0

Wechseln Sie zu Visual Studio 2015. Dies ist wahrscheinlich ein Implementierungsfehler in VS2013-Compiler.

0

Ihr Code nicht bauen eigentlich nicht mit g ++ 6.2, und der Fehler ist eindeutig genug, um zu erklären, warum man das erwartete Verhalten nicht bekommen:

foo.cc:44:15: error: taking address of temporary array 
    dummyFunc(ItemList{ 
       ^~~~~~~~~ 
     std::make_unique<Derived<int>>(2), 
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     std::make_unique<Derived<float>>(3.0f) 
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    }); 

Eine einfache Lösung wäre die Verwendung:

using ItemList = std::initializer_list<std::unique_ptr<Base>>;

anstelle eines Arrays.

aktualisieren: das Verhalten von VS könnte der richtige sein:

ein L-Wert oder R-Wert vom Typ „Array von NT“ oder „Array unbekannter von T gebunden“ kann sich auf eine umgewandelt werden Prvalue vom Typ "Zeiger auf T". Das Ergebnis ist ein Zeiger auf das erste Element des Arrays.

+0

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. –

+0

@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

+0

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. –

Verwandte Themen