Инициализация вектора non-copyable элементами
От: Tasheehoo  
Дата: 12.11.15 18:45
Оценка:
Имею такую структуру:
struct item {
   item() = delete;
   item(const item&) = delete;
   item& operator=(const item&) = delete;
   item(item&&) = default;

   const std::string data;
};

Пытаюсь инициализировать вектор таких структур:
struct db {
   static const std::vector<item> items;
};
const std::vector<item> db::items = {
    {"1"}
   ,{"2"}
};

Но компилятор говорит что нет копирующего конструктора:

error: use of deleted function 'item::item(const item&)'
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^

Оно и понятно, копирующий конструктор мне не нужен.

Но как быть?
vector initializer_list non-copyable but movable
Re: Инициализация вектора non-copyable элементами
От: andyp  
Дата: 12.11.15 19:43
Оценка:
Здравствуйте, Tasheehoo, Вы писали:


T>Оно и понятно, копирующий конструктор мне не нужен.


На сколько помню стандарт, у тебя проблемы еще на этапе создания std::initializer_list<item>. Там нужен копирующий конструктор.

T>Но как быть?


Серия вызовов push_back({"aa"}) ????

Так тоже не получится. Опять же копирование нужно.
Отредактировано 12.11.2015 19:52 andyp . Предыдущая версия .
Re[2]: Инициализация вектора non-copyable элементами
От: Tasheehoo  
Дата: 12.11.15 19:50
Оценка:
Здравствуйте, andyp, Вы писали:

A>На сколько помню стандарт, у тебя проблемы еще на этапе создания std::initializer_list<item>. Там нужен копирующий конструктор.

Нет. В initializer_list элементы инициализируются in place.
Ошибка происходит тогда, когда вектор инициализируется initializer_list-ом.

A>Серия вызовов push_back({"aa"}) ????

Это да, но неудобно и уродливо же...
Re[3]: Инициализация вектора non-copyable элементами
От: andyp  
Дата: 12.11.15 19:57
Оценка:
Здравствуйте, Tasheehoo, Вы писали:

T>Здравствуйте, andyp, Вы писали:


A>>На сколько помню стандарт, у тебя проблемы еще на этапе создания std::initializer_list<item>. Там нужен копирующий конструктор.

T>Нет. В initializer_list элементы инициализируются in place.
T>Ошибка происходит тогда, когда вектор инициализируется initializer_list-ом.

Стандарт — 8.5.4:

An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation
allocated a temporary array of N elements of type const E, where N is the number of elements in the
initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer
list, and the std::initializer_list<E> object is constructed to refer to that array. [ Note: A constructor
or conversion function selected for the copy shall be accessible
(Clause 11) in the context of the initializer
list. —end note ]


A>>Серия вызовов push_back({"aa"}) ????

T>Это да, но неудобно и уродливо же...
Re[4]: Инициализация вектора non-copyable элементами
От: Tasheehoo  
Дата: 12.11.15 20:02
Оценка:
Здравствуйте, andyp, Вы писали:

A>Стандарт — 8.5.4:

A>

A>An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation
A>allocated a temporary array of N elements of type const E, where N is the number of elements in the
A>initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer
A>list, and the std::initializer_list<E> object is constructed to refer to that array. [ Note: A constructor
A>or conversion function selected for the copy shall be accessible
(Clause 11) in the context of the initializer
A>list. —end note ]


Значит стандарт ошибается, т.к. этот код компилится, а согласно стадндарту — не должен:
std::initializer_list<item> il = {{""}, {""}};

Прошу обратить внимание на то, что item не имеет копирующего конструктора и присвающего оператора.
Re[4]: Инициализация вектора non-copyable элементами
От: watchmaker  
Дата: 12.11.15 20:09
Оценка:
Здравствуйте, andyp, Вы писали:


A>>>На сколько помню стандарт, у тебя проблемы еще на этапе создания std::initializer_list<item>. Там нужен копирующий конструктор.

T>>Нет. В initializer_list элементы инициализируются in place.
T>>Ошибка происходит тогда, когда вектор инициализируется initializer_list-ом.

A>Стандарт — 8.5.4:

A>

A>An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation
A>allocated a temporary array of N elements of type const E, where N is the number of elements in the
A>initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer
A>list, and the std::initializer_list<E> object is constructed to refer to that array. [ Note: A constructor
A>or conversion function selected for the copy shall be accessible
(Clause 11) in the context of the initializer
A>list. —end note ]


Термин copy-initialized не означает, что непременно должен использоваться копирующий конструктор. Сойдёт и перемещающий. Так что приведённый пункт стандарта никоим образом не подкрепляет твоё утверждение:

A>>>На сколько помню стандарт, у тебя проблемы еще на этапе создания std::initializer_list<item>. Там нужен копирующий конструктор.

Нет, для создания initializer_list копирующий конструктор необязателен.
Re: Инициализация вектора non-copyable элементами
От: T4r4sB Россия  
Дата: 12.11.15 20:25
Оценка:
Серия вызов emplace_back(...)?

Ну или push_back от std::move
Re: Инициализация вектора non-copyable элементами
От: watchmaker  
Дата: 12.11.15 20:26
Оценка: 10 (2) +1
Здравствуйте, Tasheehoo, Вы писали:

T>Пытаюсь инициализировать вектор таких структур:

T>Но компилятор говорит что нет копирующего конструктора:
T>Оно и понятно, копирующий конструктор мне не нужен.
Тут важно то, что по стандарту initializer_list — это принципиально константный объект. Из него нельзя сделать перемещение, так как это может поменять содержимое initializer_list.

T>Но как быть?

Инициализируешь обычный c-style массив с помощью initializer_list — тут всё ок, копирование не нужно.
Инициализируешь vector этим массивом через std::make_move_iterator — тут теперь тоже копирование не нужно.
Примерно так:
item private_items[] = { ... };
const std::vector<item> db::items(make_move_iterator(begin(private_items)), make_move_iterator(end(private_items)));


Собственно, первое действие с инициализацией C-массива как раз и показывает компилятору, что тут вместо константного списка нужно получить элементы в неком контейнере из которого можно их будет переместить. Для красоты или удобства потом можно будет создание private_items загнать в какую-нибудь функцию чтобы наружу дополнительный массив не светить.
Отредактировано 12.11.2015 20:31 watchmaker . Предыдущая версия .
Re[2]: Инициализация вектора non-copyable элементами
От: Tasheehoo  
Дата: 12.11.15 20:29
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Инициализируешь обычный c-style массив с помощью initializer_list — тут всё ок, копирование не нужно.

W>Инициализируешь vector этим массивом через std::make_move_iterator — тут теперь тоже копирование не нужно.
W>Примерно так:
W>item private_items[] = { ... };
W>const std::vector<item> db::items(make_move_iterator(begin(private_items)), make_move_iterator(end(private_items)));
W>


Да, такое решение мне нравится.

Спасибо!
Re[5]: Инициализация вектора non-copyable элементами
От: andyp  
Дата: 12.11.15 20:35
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Термин copy-initialized не означает, что непременно должен использоваться копирующий конструктор. Сойдёт и перемещающий. Так что приведённый пункт стандарта никоим образом не подкрепляет твоё утверждение:

A>>>>На сколько помню стандарт, у тебя проблемы еще на этапе создания std::initializer_list<item>. Там нужен копирующий конструктор.

W>Нет, для создания initializer_list копирующий конструктор необязателен.


На счет "сойдет и перемещающий" ничего в стандарте не нашел . copy-initialize упоминается в контекстах, предполагающих копирование.
Re[5]: Инициализация вектора non-copyable элементами
От: andyp  
Дата: 12.11.15 20:36
Оценка:
Здравствуйте, Tasheehoo, Вы писали:

T>Значит стандарт ошибается, т.к. этот код компилится, а согласно стадндарту — не должен:

T>
T>std::initializer_list<item> il = {{""}, {""}};
T>

T>Прошу обратить внимание на то, что item не имеет копирующего конструктора и присвающего оператора.

Либо компилятор работает не совсем по стандарту, либо тебе нужен лучший language lawyer, чем я.
Re[3]: Инициализация вектора non-copyable элементами
От: B0FEE664  
Дата: 13.11.15 17:29
Оценка:
Здравствуйте, Tasheehoo, Вы писали:

W>>Примерно так:
W>>item private_items[] = { ... };
W>>const std::vector<item> db::items(make_move_iterator(begin(private_items)), make_move_iterator(end(private_items)));
W>>


T>Да, такое решение мне нравится.

T>Спасибо!

Всё это очень хорошо, но мне осталось не понятно, зачем const std::vector, а не const std::array.
И каждый день — без права на ошибку...
Re[4]: Инициализация вектора non-copyable элементами
От: Tasheehoo  
Дата: 14.11.15 21:31
Оценка: :))
Здравствуйте, B0FEE664, Вы писали:

BFE>Всё это очень хорошо, но мне осталось не понятно, зачем const std::vector, а не const std::array.

Правильный вопрос! А главное — вовремя!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.