Под пересылкой на месте строительства, я понимаю станд :: Распределитель :: конструкт и различные методы emplace, например, станд :: вектор :: emplace_back. Я просто обнаружил, что перенаправленная конструкция на месте в C ++ не (не может?) Использовать синтаксис инициализации списка. В результате кажется, что никогда нельзя пересылать на месте конструкцию агрегата. Я просто хочу убедиться, что перенаправленная конструкция на месте не поддерживает инициализацию списка и, следовательно, агрегированные типы. Это связано с ограниченностью языка? Может ли кто-нибудь предоставить ссылку на стандарт по этому вопросу? Ниже приводится иллюстрация:
В то время как мы можем сделать строительство на месте непосредственно
int(*p)[3] = ...;
new(p) int[3]{1, 2, 3};
мы не можем сделать пересылку на месте строительства, как
std::allocator<int[3]> allo;
allo.construct(p, 1, 2, 3);
В то время как {}
был назван единым синтаксисом инициализации, он далеко не универсален.
возьмите эти два примера:
size_t a = 3;
size_t b = 1;
std::vector<size_t> v1{a,b};
std::vector<size_t> v2(a,b);
в первом случае мы строим вектор, содержащий два элемента, 3
а также 1
,
Во втором случае мы создаем вектор, содержащий 1,1,1
— 3 копии 1
,
Так {}
основанная конструкция может вызвать другое поведение, чем ()
на основе строительства в некоторых случаях. Более того, в приведенном выше случае нет способа достичь синтаксиса «3 копии из 1», используя {}
строительство (что я знаю). Но {3,2}
регистр можно обработать, просто явно создав список инициализаторов и передав его ()
,
Поскольку большинство типов, которые принимают списки инициализаторов, могут быть построены с помощью явной передачи в списке инициализаторов, а стандартная библиотека C ++ была разработана для типов с конструкторами больше, чем типы без них, стандартная библиотека C ++ почти равномерно использует конструкции, используя ()
и не {}
,
Недостатком является то, что типы, которые хотят быть инициализированными списком, не могут быть задействованы с помощью этого механизма.
Теоретически, list_emplace
методы, которые конструируют с использованием {}
вместо этого можно добавить к каждому интерфейсу. Я призываю вас сделать это!
std::allocator
«s construct()
(а также реализация по умолчанию, предоставляемая std::allocator_traits
) указано использовать ()
: ::new((void *)p) U(std::forward<Args>(args)...)
(см. [allocator.members] / p12, [allocator.traits.members] / p5).
Нецелесообразно менять его на {}
на данный момент, потому что он будет молча сломать существующий код:
std::vector<std::vector<int>> foo;
foo.emplace_back(10, 10); // add a vector of ten 10s with (); two 10s with {}
Есть вопрос LWG чтобы заставить его вернуться к использованию {}
если ()
не работает Посмотрим, согласен ли комитет с этим направлением.
@Yakk указывает на потенциальные недостатки этого подхода:
foo.emplace_back(10); // ten 0s
foo.emplace_back(10, 10); // ten 10s
foo.emplace_back(10, 10, 10); // three(!) 10s
Аналогичная проблема (см. Приложение B N2215) привело к решению, что инициализация списка всегда будет предпочтительнее initializer_list
Конструкторы.