2016-11-05 67 views
0

我想傳遞一個數組到一個函數,並防止每次寫「std :: unique_ptr」,並使內聯建設成爲可能,我介紹了一個typedef( ItemList)來爲數組別名。C++ 11列表初始化在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; 
} 

這可以按照打算在調試版本中打印和打印;

Base ctor 
Derived ctor2 
Base ctor 
Derived ctor2 
Derived dtor2 
Base dtor 
Derived dtor2 
Base dtor 

到目前爲止好。但是當我以釋放模式(使用所有本機編譯器)構建它時,

Base ctor 
Derived ctor2 
Base ctor 
Derived ctor3 
Derived dtor2 
Base dtor 

退出數組生命週期後,數組中的第二項不會被破壞。 使其按照我的預期工作的唯一方法是使用C++ 03樣式初始化或調試模式;

ItemList tmpList = { 
    std::make_unique<Derived<int>>(2), 
    std::make_unique<Derived<float>>(2.0f) 
}; 

dummyFunc(tmpList); 

這導致了預期的行爲(所有析構函數被調用)。

我還沒有用任何其他編譯器測試過,但這是預期的行爲?我做錯了什麼,或者我錯過了什麼?

更新:

有趣dtors被稱爲與基地實例預期;

dummyFunc(ItemList{ 
    std::make_unique<Base>(), 
    std::make_unique<Base>() 
}); 

輸出;

Base ctor 
Base ctor 
Base dtor 
Base dtor 

剛剛初始化數組(無函數調用)的行爲與函數調用的行爲相同。

回答

0

切換到Visual Studio 2015.這可能是VS2013編譯器中的一個實現錯誤。

0

你的代碼實際上不使用g ++ 6.2編譯和誤差足夠明確的解釋爲什麼你沒有得到預期的行爲:

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) 
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    }); 

一個簡單的解決方法是使用:

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

而不是數組。

更新:VS的行爲可能是正確的:

左值或類型的右值「陣列NT的」或「未知的陣列結合的T 」可以被轉換爲一個「指向T的指針」類型的值。結果 是指向數組的第一個元素的指針。

+0

有趣......它在win和mac默認編譯器上編譯。不確定在Mac上的發佈行爲,但會檢查。還沒有嘗試過你的解決方案。另一方面,我不確定它是否真的應該抱怨使用臨時數組。這是我的問題,警告會是一個更好的行爲。應該檢查這種行爲的標準。 –

+0

@AliNaciErdem取一個右值的地址是非法的,參考標準:「一元&運算符的結果是一個指向其操作數的指針。操作數應該是一個左值或者是一個合格的id。關於VS在release中的行爲,我更新了我的答案。 – AntiClimacus

+0

這仍然不能解釋行爲。如果它被轉換爲第一個元素的指針,那麼爲什麼第一個元素被破壞?我沒有明白。沒關係,如果對象在被傳遞給func之前被破壞,但它應該被銷燬,因爲它被分配到堆棧中。 –