Я пытаюсь передать массив функции и не допускать запись «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;
}
Это работает в соответствии с сборкой и отпечатками Debug;
Base ctor
Derived ctor2
Base ctor
Derived ctor2
Derived dtor2
Base dtor
Derived dtor2
Base dtor
Пока все хорошо. Но когда я создаю это в режиме Release (со всеми родными компиляторами), я получаю;
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);
Это приводит к предполагаемому поведению (все деструкторы называются).
Я еще не тестировал это с каким-либо другим компилятором, но это ожидаемое поведение? Что я делаю неправильно, или я чего-то не хватает?
Update:
Интересно dtors называются, как и ожидалось с базовыми экземплярами;
dummyFunc(ItemList{
std::make_unique<Base>(),
std::make_unique<Base>()
});
Выходы;
Base ctor
Base ctor
Base dtor
Base dtor
И только инициализация массива (без вызова функции) ведет себя так же, как при вызове функции.
Интересно ... Он компилируется как по умолчанию, так и по умолчанию. Не уверен относительно поведения релиза на Mac, но будет проверять. Havent попробовал ваше решение. С другой стороны, я не уверен, действительно ли он должен жаловаться на использование временного массива. Это моя проблема, предупреждение будет лучшим поведением. Следует проверить стандарт на это поведение. –
@AliNaciErdem, принимающий адрес rvalue, является незаконным, cf стандартом: 'Результат оператора unary & является указателем на его операнд. Операнд должен быть lvalue или квалифицированным идентификатором. «О поведении VS в выпуске я обновил свой ответ. – AntiClimacus
Это все еще не объясняет поведение. Если он преобразуется в указатель на первый элемент, то почему первый элемент разрушен? Я не понимаю. Im хорошо, если объект будет уничтожен до передачи в func, но он должен быть уничтожен, так как он выделен в стеке. –