std :: initializer_list уничтожает содержащие объекты до конца области действия в clang - PullRequest
1 голос
/ 14 марта 2019

Как показано в следующем коде, содержащие std :: initializer_list объекты уничтожаются даже до завершения области действия. Я хотел бы знать, не соответствует ли код стандарту или это ошибка в clang (так как он прекрасно работает с gcc и vc).

#include <iostream>

class Attrib
{
public:
    Attrib()
    {
        std::cout<< "Constructor called"<< std::endl;
    }

    Attrib(const Attrib& r)
    {
        std::cout<< "Copy constructor called"<< std::endl;
    }

    ~Attrib()
    {
        std::cout<< "Destructor called"<< std::endl;
    }
};

int main()
{
    auto attribs = std::initializer_list<Attrib>({Attrib()});
    std::cout<< "Before returning from main"<< std::endl;
    return 0;
}

Выход в лязг ,

Constructor called
Destructor called
Before returning from main

Вывод в gcc,

Constructor called
Before returning from main
Destructor called

EDIT: Если мы немного изменим строку создания initializer_list в main следующим образом,

     std::initializer_list<Attrib> attribs = {Attrib()};

Выход в CLang равен,

Constructor called
Before returning from main
Destructor called

Ответы [ 2 ]

1 голос
/ 14 марта 2019

Это ошибка в Clang.Возможно 31636 или 40562 .

auto attribs = std::initializer_list<Attrib>({Attrib()});

Это инициализация копирования attribs из инициализатора std::initializer_list<Attrib>({Attrib()}).После C ++ 17 гарантированного копирования elision , это эквивалентно инициализации копирования attribs из {Attrib()}.

[dcl.init.list]

¶5 Объект типа std::initializer_list<E> создается из списка инициализаторов так, как если бы реализация генерировала и материализовала значение типа «массив из N const E», где N - количество элементов в списке инициализатора.Каждый элемент этого массива инициализируется копией с соответствующим элементом списка инициализатора, и объект std::initializer_list<E> создается для ссылки на этот массив.

¶6 Массив имеет то же время жизни, что и любой другой временныйобъект, за исключением того, что инициализация initializer_list объекта из массива продлевает время жизни массива точно так же, как привязка ссылки к временному объекту.

Согласно CWG1565 :

Q.Если объект initializer_list копируется и копия удаляется, увеличивается ли время жизни базового объекта массива?

A.Консенсус CWG заключался в том, что поведение должно быть одинаковым, независимо от того, была ли удалена копия.

Как вы заметили в своем EDIT, Clang ведет себя правильно, когда мыудалите лишнюю «копию»:

auto attribs = std::initializer_list<Attrib>{Attrib()};
0 голосов
/ 14 марта 2019

Ошибка в вашей программе. std::initializer_list не требуется для глубокого копирования его оператора присваивания, это легкий прокси-объект.

В результате семантически ваши Attrib объекты уничтожаются сразу после окончания строки auto attribs = std::initializer_list... (когда уничтожаются их временные объекты). Так что clang семантически правильно.

Причина, по которой gcc дает вам другой вывод, наиболее вероятна из-за включенной оптимизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...