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

Код

#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< /strong> и параметр --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 для пустого списка инициализаторов?

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


person apriori    schedule 29.01.2016    source источник
comment
В случае исключения вам, возможно, придется уничтожить B, поэтому требуется его определение.   -  person Jarod42    schedule 29.01.2016
comment
Другими словами, деструктор также должен быть полностью определен, и для этого unique_ptr нужен полный тип, см. stackoverflow.com/questions/9954518/ @Jarod42 Вы должны опубликовать ответ, так как это хороший вопрос и не такой очевидный.   -  person vsoftco    schedule 29.01.2016
comment
К вашему сведению: std::list<std::unique_ptr<B>> bs{}; вызовет конструктор по умолчанию. В соответствии с 13.3.1.7 стандарта C++14, если пустой список инициализации в фигурных скобках передается типу, имеющему конструктор по умолчанию, то именно он и будет вызываться.   -  person Nicol Bolas    schedule 29.01.2016
comment
std::list<std::unique_ptr<B>> bs; тоже должен вызывать конструктор по умолчанию, верно? Почему тогда не работает тот, что с {}?   -  person apriori    schedule 29.01.2016
comment
@apriori В качестве объявления члена std::list<std::unique_ptr<B>> bs; не вызывает никакого конструктора.   -  person T.C.    schedule 29.01.2016
comment
@Т.С. Это нестатическое определение члена данных, см. [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 вызывается [...]   -  person apriori    schedule 29.01.2016
comment
По вашей логике у вас не может быть нестатического члена данных типа без конструктора по умолчанию, что совершенно бессмысленно.   -  person T.C.    schedule 29.01.2016
comment
@Т.С. Я цитирую стандарт с [...] объектом типа класса (возможно, cv-qualified) (или его массивом) [...]. У вас есть пример нестатического члена данных типа класса без конструктора по умолчанию? struct X { X() = delete; }; class A { X x; }; int main() { A a; return 0; } определенно не работает.   -  person apriori    schedule 30.01.2016
comment
Вам действительно нужна помощь, чтобы придумать пример??? struct X <% X(int); %>; class A <% X x; public: A() : x(0) <%%> %> a; Я думаю, что вы должны сначала выучить язык, прежде чем пытаться его языковым юристом.   -  person T.C.    schedule 30.01.2016
comment
Теперь вы игнорируете часть Когда не указан инициализатор [...]. Я думал, что это будет ясно из контекста, когда я писал свой последующий комментарий. Спасибо за участие, но с таким грубым отношением я бы предпочел не продолжать с вами дискуссию.   -  person apriori    schedule 30.01.2016
comment
В X x; также не указан инициализатор. Единственная разница между этим и вашим кодом в том, что я дал конструктору определение, а вы нет.   -  person T.C.    schedule 30.01.2016
comment
@Т.С. Не в X x;, а после конструктора в ctor-initializer. [class.base.init] 12.6.2 (1): в определении конструктора для класса инициализаторы для прямых и виртуальных базовых подобъектов и нестатические элементы данных может быть указан ctor-initializer. Это то, что вы сделали, и именно поэтому конструктор default не понадобился.   -  person apriori    schedule 30.01.2016
comment
@apriori Верно и не совсем относится к моей точке зрения. Я пытаюсь подчеркнуть, что struct A { X x; A(); } a; - в вашем случае - не вызывает конструктор по умолчанию X (или не требует, чтобы он был). Конструктор, вызываемый для x, полностью зависит от того, как написано A::A().   -  person T.C.    schedule 30.01.2016
comment
@Т.С. Правильно, именно поэтому я написал, что в моем вопросе должен вызываться стандартный конструктор std::list, поэтому я принял определение A::A() = default. Без этого предположения ваш комментарий std::list<std::unique_ptr<B>> bs; не вызывает никакого конструктора и может быть истолкован как что-то вроде std::list<std::unique_ptr<B>> bs; не вызывает никакого конкретного конструктора , потому что вызываемый конструктор может быть определен необязательный ctor-initializer, указанный в реализации ctor., что является правильным для IMO.   -  person apriori    schedule 30.01.2016
comment
@apriori Ну, в вашем вопросе это не по умолчанию (и на самом деле, если бы вы сделали это по умолчанию, вы бы увидели одни и те же ошибки в обоих случаях!)   -  person T.C.    schedule 30.01.2016


Ответы (1)


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

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

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

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

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

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

person Howard Hinnant    schedule 29.01.2016
comment
Большое спасибо, Говард, это было именно то, что я искал. Похоже, что этот вопрос уже давно не решен. - person apriori; 30.01.2016
comment
CWG1396 посвящен шаблонам классов. A в примере ОП не является шаблоном. Аргументы функций по умолчанию, например, не создаются до тех пор, пока они не потребуются для шаблонов функций, но проверяются для функций. void f(double = ""); имеет неправильный формат, даже если вы никогда не вызываете его таким образом, который требует использования аргумента по умолчанию. - person T.C.; 30.01.2016
comment
@T.C.: Возможно. Я не регулярно присутствую на собраниях CWG, поэтому не очень хорошо знаком с этим вопросом. Я запускаю заголовок CWG1396: отложенное создание экземпляров и проверка инициализаторов нестатических элементов данных, которые можно интерпретировать как относящиеся к коду OP. Я приветствую другие теории или мнения тех, кто лучше, чем я, связан с CWG. - person Howard Hinnant; 30.01.2016