Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Std::list‹std::unique_ptr›: пустой список инициализаторов вместо конструктора по умолчанию

Автор вопроса: aprioriОтветов: 1

Код

#include <list>
#include <memory>

class B;
class A {
    std::list<std::unique_ptr<B>> bs;
public:
    A();
    ~A();
};

int main()
{
    A x;
    return 0;
}

очевидно компилируется. Это не связано, потому что A::A() и A::~A() отсутствуют, но это ожидаемо и хорошо. изменение

std::list<std::unique_ptr<B>> bs;

который должен вызывать стандартный конструктор std::list

list() : list(Allocator()) {}

(С++ 14 и выше) до

std::list<std::unique_ptr<B>> bs{};

который должен вызывать list(std::initializer_list, const Allocator & = Allocator()); также конструктор по умолчанию. (Спасибо Nicol Bolas, который правильно сослался на [over.match.list] 13.3.1.7) дает следующую ошибку с c++ (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010 и параметр --std=c++17:

/usr/include/c++/5/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = B]’:
/usr/include/c++/5/bits/unique_ptr.h:236:17:   required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = B; _Dp = std::default_delete<B>]’
/usr/include/c++/5/bits/stl_list.h:106:12:   required from ‘void __gnu_cxx::new_allocator<_Tp>::destroy(_Up*) [with _Up = std::_List_node<std::unique_ptr<B> >; _Tp = std::_List_node<std::unique_ptr<B> >]’
/usr/include/c++/5/bits/list.tcc:75:4:   required from ‘void std::__cxx11::_List_base<_Tp, _Alloc>::_M_clear() [with _Tp = std::unique_ptr<B>; _Alloc = std::allocator<std::unique_ptr<B> >]’
/usr/include/c++/5/bits/stl_list.h:446:17:   required from ‘std::__cxx11::_List_base<_Tp, _Alloc>::~_List_base() [with _Tp = std::unique_ptr<B>; _Alloc = std::allocator<std::unique_ptr<B> >]’
/usr/include/c++/5/bits/stl_list.h:507:11:   required from here
/usr/include/c++/5/bits/unique_ptr.h:74:22: error: invalid application of ‘sizeof’ to incomplete type ‘B’
  static_assert(sizeof(_Tp)>0,
                      ^

Который лает о том, что тип B неполный. Мой вопрос:

Почему конструктору initializer_list нужен полный тип B для пустого списка инициализаторов?

Всегда приветствуются указатели на соответствующие части стандарта.

  • В случае исключения вам, возможно, придется уничтожить B, поэтому требуется его определение. Jarod42 29.01.2016
  • Другими словами, деструктор также должен быть полностью определен, и для этого unique_ptr нужен полный тип, см. stackoverflow.com/questions/9954518/ @Jarod42 Вы должны опубликовать ответ, так как это хороший вопрос и не такой очевидный. vsoftco 29.01.2016
  • К вашему сведению: std::list<std::unique_ptr<B>> bs{}; вызовет конструктор по умолчанию. В соответствии с 13.3.1.7 стандарта C++14, если пустой список инициализации в фигурных скобках передается типу, имеющему конструктор по умолчанию, то именно он и будет вызываться. Nicol Bolas 29.01.2016
  • std::list<std::unique_ptr<B>> bs; тоже должен вызывать конструктор по умолчанию, верно? Почему тогда не работает тот, что с {}? apriori 29.01.2016
  • @apriori В качестве объявления члена std::list<std::unique_ptr<B>> bs; не вызывает никакого конструктора. T.C. 29.01.2016
  • @Т.С. Это нестатическое определение члена данных, см. [basic.def] 3.1 (2). [class.init] 12.6 (1) говорит: когда инициализатор не указан для объекта типа класса (возможно, с указанием cv) (или его массива) или инициализатор имеет форму (), объект инициализируется, как указано в 8.5., [decl.init] 8.5 (12) говорит Если для объекта не указан инициализатор, объект инициализируется по умолчанию. [dcl.init] 8.5 (7.1) продолжается: если T является типом класса (возможно, cv-квалифицированным) (пункт 9), конструктор по умолчанию (12.1) для T вызывается [...] apriori 29.01.2016

c++c++17unique-ptr

Ответы

Ответ 1 · рейтинг 2 · Howard Hinnant

Я думаю, вы ступили на передний край.

Похоже, это активный вопрос в CWG (Основная рабочая группа комитета C++).

CWG 1396, по-видимому, озабочен именно этим проблема. Эта проблема связана с CWG 1360, в которой говорится часть:

Проблема усугубляется шаблонами классов, поскольку текущее направление CWG заключается в создании экземпляров инициализаторов элементов только тогда, когда они необходимы (см. проблему 1396).

В вашем примере инициализатор bs никогда не нужен, и, таким образом, согласно упомянутому выше "направлению", не следует никогда не создавать экземпляр. Просто сегодня нас еще нет. Обе эти проблемы имеют статус редакторы, что означает: они работают над этим.

FWIW, VS-2015, как сообщается на http://webcompiler.cloudapp.net, компилирует (но, конечно, не связывает ) этот пример.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы