Будьте осмотрительны, используя initializer_list для инициализации. Помните, его элементы всегда копируются, а не перемещаются, даже когда вы наполняете его rvalue значениями:
struct MovableNonCopyable
{
MovableNonCopyable() = default;
MovableNonCopyable(MovableNonCopyable&&) = default;
};
// . . .
std::vector<MovableNonCopyable> v { MovableNonCopyable(), MovableNonCopyable(), MovableNonCopyable() };
// error: use of deleted function ‘constexpr MovableNonCopyable::MovableNonCopyable(const MovableNonCopyable&)’
Здравствуйте, rg45, Вы писали:
R>Будьте осмотрительны, используя initializer_list для инициализации. Помните, его элементы всегда копируются, а не перемещаются, даже когда вы наполняете его rvalue значениями:
R>
R>struct MovableNonCopyable
R>{
R> MovableNonCopyable() = default;
R> MovableNonCopyable(MovableNonCopyable&&) = default;
R>};
R>// . . .
R>std::vector<MovableNonCopyable> v { MovableNonCopyable(), MovableNonCopyable(), MovableNonCopyable() };
R>// error: use of deleted function ‘constexpr MovableNonCopyable::MovableNonCopyable(const MovableNonCopyable&)’
R>
Это std::vector<T> требует:
T must meet the requirements of CopyAssignable and CopyConstructible.
Здравствуйте, rg45, Вы писали:
R>Будьте осмотрительны, используя initializer_list для инициализации. Помните, его элементы всегда копируются, а не перемещаются, даже когда вы наполняете его rvalue значениями
Ок. Тогда вопрос: как проинициализировать вектор элементом используя перемещение?
Здравствуйте, YuriV, Вы писали:
YV>Это std::vector<T> требует: YV>
YV>T must meet the requirements of CopyAssignable and CopyConstructible.
Это актуально до C++11.
(Since C++11) (until C++17):
The requirements that are imposed on the elements depend on the actual operations performed on the container. Generally, it is required that element type is a complete type and meets the requirements of Erasable, but many member functions impose stricter requirements.
Работоспособен, но конструкторы копирования/перемещения MovableNonCopyable, похоже, не вызываются, потому как тут и не std::initializer_list вовсе, а aggregate initialization.
Здравствуйте, Videoman, Вы писали:
V>Здравствуйте, rg45, Вы писали:
R>>Будьте осмотрительны, используя initializer_list для инициализации. Помните, его элементы всегда копируются, а не перемещаются, даже когда вы наполняете его rvalue значениями
V>Ок. Тогда вопрос: как проинициализировать вектор элементом используя перемещение?
Здравствуйте, YuriV, Вы писали:
YV>Здравствуйте, rg45, Вы писали:
R>>Будьте осмотрительны, используя initializer_list для инициализации. Помните, его элементы всегда копируются, а не перемещаются, даже когда вы наполняете его rvalue значениями:
R>>
R>>struct MovableNonCopyable
R>>{
R>> MovableNonCopyable() = default;
R>> MovableNonCopyable(MovableNonCopyable&&) = default;
R>>};
R>>// . . .
R>>std::vector<MovableNonCopyable> v { MovableNonCopyable(), MovableNonCopyable(), MovableNonCopyable() };
R>>// error: use of deleted function ‘constexpr MovableNonCopyable::MovableNonCopyable(const MovableNonCopyable&)’
R>>
YV>Это std::vector<T> требует: YV>
YV>T must meet the requirements of CopyAssignable and CopyConstructible.
Да не вопрос, сделай конструктор копирования доступным в классе, ошибка исчезнет. Но выполняться будет копирование, а не перемещение, как, вероятно кто-то ожидает — вот в этом проблема.
YV>а такой код вполне работоспособен: YV>
Не, ну "засадить" опосля я и сам могу. Я имею ввиду именно при инициализации, в конструкторе. Просто у меня часто бывает начальная инициализация вектора одним элементом:
MyClass::MyClass() : m_vec(/* как тут инициализировать ???*/) {} // в списке инициализации
или
func1(func2(Vec(/* как тут инициализировать ???*/))); // в каскаде вызовов
Для себя, кроме как создать функцию и там уже сделать emplace_back, и из нее уже вернуть вектор как R-Value, я ничего удобного не нашел
Здравствуйте, Videoman, Вы писали:
V>Не, ну "засадить" опосля я и сам могу. Я имею ввиду именно при инициализации, в конструкторе. Просто у меня часто бывает начальная инициализация вектора одним элементом: V>
V>MyClass::MyClass() : m_vec(/* как тут инициализировать ???*/) {} // в списке инициализации
V>
V>или V>
V>func1(func2(Vec(/* как тут инициализировать ???*/))); // в каскаде вызовов
V>
Увы и ах, выходит, что никак.
V>Для себя, кроме как создать функцию и там уже сделать emplace_back, и из нее уже вернуть вектор как R-Value, я ничего удобного не нашел
Ну можно еше поизвращаться с initializer_list-ом прокси-объектов. Но в этом варианте свои минусы.
Здравствуйте, Videoman, Вы писали:
V>Здравствуйте, rg45, Вы писали:
R>>Ну можно еше поизвращаться с initializer_list-ом прокси-объектов. Но в этом варианте свои минусы.
V>Да, я в курсе. Казалось бы, базовые операции. Какой-то привкус недодела чувствуется.
Интересно, если в С++20 примут Ranges, то добавят ли в контейнеры конструкторы с Range? Кто-нибудь в курсе?
Здравствуйте, rg45, Вы писали:
R>Потому, что это aggregate initialization, с ним все в порядке, в отличие от list initialization. Они хоть по форме и похожи, путать не рекоммендуется
Ад с этими всеми инициализациями какой-то. Каждый раз читаю, всё понимаю, через полчаса в голове снова ничего И так раз 800 у меня уже было.
Здравствуйте, andyp, Вы писали:
R>>Потому, что это aggregate initialization, с ним все в порядке, в отличие от list initialization. Они хоть по форме и похожи, путать не рекоммендуется
A>Ад с этими всеми инициализациями какой-то. Каждый раз читаю, всё понимаю, через полчаса в голове снова ничего И так раз 800 у меня уже было.
Так просто ведь все — aggregate initialization — это старая добрая си-шная инициализация массивов и структур. А list initialization — уродец, основанный на initializer_list-ах, придуманный каким-то студентом, для которого шашечки важнее, чем ехать. Это сугубо мое мнение, если что.
Здравствуйте, rg45, Вы писали:
R>Так просто ведь все — aggregate initialization — это старая добрая си-шная инициализация массивов и структур. А list initialization — уродец, основанный на initializer_list-ах, придуманный каким-то студентом, для которого шашечки важнее, чем ехать.
Это если только на эти две смотреть. А так там еще default, zero, value, direct, constant... Тьма их. В общем, ты толкнул меня на 801 круг
Здравствуйте, YuriV, Вы писали:
YV>Здравствуйте, ViTech, Вы писали:
VT>>Работоспособен, но конструкторы копирования/перемещения MovableNonCopyable, похоже, не вызываются,
YV>вызываются, ...
Здравствуйте, ViTech, Вы писали:
VT>Вот тут не вызываются. Или я что-то не так делаю? VT>Это может зависеть от используемого компилятора, опций компиляции.
Нет, нет конструкторы копирования не вызываются, это я туплю.
Здравствуйте, ViTech, Вы писали:
VT>Вот тут не вызываются. Или я что-то не так делаю?
Здесь просиходит тот самый copy/move elision, описанный в разделе 15.8.3. Компилятор, всместо того, чтобы сначала создавать временные объекты, а потом перемещать их, сразу конструирует объекты по месту назначения. И это еще раз демонстрирует существенную неравнозначность между aggregation и list инициализациями.
R>Здесь просиходит тот самый copy/move elision, описанный в разделе 15.8.3.
В разделе 15.8.3 Камасутры? Какая версия стандарта?
Ладно. Возьмём 2017-й.
This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):
— in a return statement …
— in a throw-expression …
— when the exception-declaration of an exception handler …
Не подходит.
Мув-констрактор не вызывается из-за параграфа 17.6.1 раздела 11.6. 2017-го стандарта.
> И это еще раз демонстрирует существенную неравнозначность между aggregation и list инициализациями.
Здравствуйте, Videoman, Вы писали:
V>Для себя, кроме как создать функцию и там уже сделать emplace_back, и из нее уже вернуть вектор как R-Value, я ничего удобного не нашел
Здравствуйте, B0FEE664, Вы писали: V>>Для себя, кроме как создать функцию и там уже сделать emplace_back, и из нее уже вернуть вектор как R-Value, я ничего удобного не нашел BFE>Это так, что ли?: BFE>