Могу ли я создать вектор, содержащий элементы, которые не могут быть скопированы и не имеют конструктора по умолчанию в C ++ 11?
пример:
#include <iostream>
#include <string>
#include <vector>
struct value {
value() = delete;
~value() = default;
value(value const&) = delete;
value& operator =(value const&) = delete;
explicit value(int i) : i_(i) {}
private:
int i_;
};
int main() {
std::vector<value> v;
v.reserve(10);
for (unsigned i = 0; i < 10; ++i)
v.emplace_back(7);
}
и здесь я хочу создать 10 значений и каждое значение ctor передать целое число 7 …
std::vector< value > v(in-place, 10, 7)
Почему в конструктор std :: vector не была добавлена форма построения размещения C ++ 11
Ошибки вставлены из coliru:
+ g++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
In file included from /usr/include/c++/4.8/vector:62:0,
from main.cpp:3:
/usr/include/c++/4.8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = value; _Args = {value}]’:
/usr/include/c++/4.8/bits/stl_uninitialized.h:75:53: required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<value*> _ForwardIterator = value*; bool _TrivialValueTypes = false]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:117:41: required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<value*> _ForwardIterator = value*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:258:63: required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<value*> _ForwardIterator = value*; _Tp = value]’
/usr/include/c++/4.8/bits/stl_vector.h:1142:29: required from ‘std::vector<_Tp, _Alloc>::pointer std::vector<_Tp, _Alloc>::_M_allocate_and_copy(std::vector<_Tp, _Alloc>::size_type, _ForwardIterator, _ForwardIterator) [with _ForwardIterator = std::move_iterator<value*> _Tp = value; _Alloc = std::allocator<value> std::vector<_Tp, _Alloc>::pointer = value*; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/usr/include/c++/4.8/bits/vector.tcc:75:70: required from ‘void std::vector<_Tp, _Alloc>::reserve(std::vector<_Tp, _Alloc>::size_type) [with _Tp = value; _Alloc = std::allocator<value> std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
main.cpp:24:17: required from here
/usr/include/c++/4.8/bits/stl_construct.h:75:7: error: use of deleted function ‘value::value(const value&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
main.cpp:11:5: error: declared here
value(value const&) = delete;
^
Причина, по которой вы получаете ошибки, заключается в том, что использование emplace_back
на std::vector
требует, чтобы тип элемента был как минимум MoveConstructible. Это необходимо, если вектор должен расти и перераспределять свои элементы.
Добавить переместить конструктор вам структура, и вы сможете использовать ее в своем коде (реализация по умолчанию будет достаточно для вашего кода).
value(value&&) = default;
Компилятор не будет явно генерировать конструктор перемещения по умолчанию для вашей структуры, как вы объявили свой собственный конструктор копирования, value(value const&) = delete
(=delete
а также =default
считать как пользователь), а также оператор копирования и деструктор.
Для получения дополнительной информации о правилах генерации неявного конструктора перемещения смотрите здесь: Почему по умолчанию нет перемещения-назначения / перемещения-конструктора?
С помощью std::vector
конструктор формы std::vector(size_t count, const T& value)
копирует значения в вектор и требует, чтобы тип элемента был CopyConstructible.
Да, изменение размера и т. Д. Можно все они обрабатываются с помощью Move вместо конструктора / присваивания копирования, если вы его определили (что бы ни говорил cppreference).
#include <vector>
#include <iostream>
struct value {
int i_;
explicit value(int i) : i_(i) {std::cout<<"value::value(" <<i_<<")\n"; }
value(value &&src) : i_(src.i_) {std::cout<<"value::value(&&"<<i_<<")\n"; }
value(value const&) = delete;
value& operator=(value const&) = delete;
value& operator=(value &&src) {
i_ = src.i_;
std::cout << "value::=(&&" << i_ << ")\n";
return *this;
}
value() = delete;
};
int main() {
std::vector<value> v;
v.reserve(1);
v.emplace_back(1);
v.emplace_back(2);
v.emplace_back(3);
}
работает отлично:
value::value(1) <-- emplace_back(1)
value::value(2)
value::value(&&1) <-- emplace_back(2) inc. resize & move 1
value::value(3)
value::value(&&1)
value::value(&&2) <-- emplace_back(3) inc. resize & move 1,2
До поддержки перемещения, если бы элементы вектора не были копируемыми, он не смог бы изменить свой размер (или стереть элементы, или выполнить довольно много его интерфейса).
Да, вы можете поместить объекты, которые нельзя копировать или конструировать по умолчанию, в vector
в C ++ 11, если они являются подвижными:
#include <iostream>
#include <string>
#include <vector>
struct value {
value() = delete;
~value() = default;
value(value const&) = delete;
value& operator =(value const&) = delete;
// Move construction and assignment
value(value&&) = default;
value& operator =(value&&) = default;
explicit value(int i) : i_(i) {}
private:
int i_;
};
int main() {
std::vector<value> v;
v.reserve(10);
for (unsigned i = 0; i < 10; ++i)
v.emplace_back(7);
}
Но вы не можете использовать конструктор, который заполняет такой вектор копиями заданного значения — так как значения не могут быть скопированы. Точно так же вы не можете вырастить вектор таких объектов с resize
,
Напишите конструктор перемещения и затем используйте emplace_back
:
struct value
{
...
value(value && obj) : i_(obj.i_)
{
}
or
value(value && obj) = default;
...
};
std::vector<value> v;
for (int i=0; i<10; i++)
v.emplace_back(7);