2

Can I create vector that contains elements that are noncopyable and don't have a default constructor in C++11?

example:

#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); } 

and here I want to create 10 values and each to value ctor pass the integer 7 ...

std::vector< value > v(in-place, 10, 7) 

Why wasn't the C++11 placement construction form added to this std::vector constructor

Errors pasted from 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; ^ 
2
  • All the answers so far assume that the items are (or can sensibly be made to be) moveable. I'd like to see an answer without this assumption. Commented Mar 27, 2015 at 22:22
  • That sounds like a separate question - why don't you ask it? Commented Mar 28, 2015 at 17:06

4 Answers 4

3

The reason you get errors is that using emplace_back on a std::vector requires the element type to be at least MoveConstructible. This is needed if the vector needs to grow and reallocate its elements.

Add a move constructor to you struct and you will be able to use it in your code (the default implementation will suffice for your code).

value(value&&) = default; 

The compiler will not implicitly generate a default move constructor for your struct as you have declared your own copy constructor, value(value const&) = delete (=delete and =default count as user-declared), as well as a copy assignment operator and a destructor.

For more info about the rules of implicit move constructor generation, look here: Why no default move-assignment/move-constructor?


Using std::vector's constructor of the form std::vector(size_t count, const T& value) copies the values into the vector, and requires the element type to be CopyConstructible.

Sign up to request clarification or add additional context in comments.

1 Comment

Declaring a constructor does not in general suppress generation of the default move constructor: declaring a copy constructor does suppress generation of a default move constructor (§12.8p9).
2

Yes, the resizing etc. can all be handled with move instead of copy constructor/assignment, if you define it (whatever cppreference says).

#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); } 

works fine:

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 

Motivation for the requirement

Before move support, if a vector's elements were non-copyable, it would be unable to resize itself (or erase items, or fulfill quite a lot of its interface).

7 Comments

std::array is only static size, if I need dynamic size I can't use it.
I missed that you hadn't defined move constructor & assignment, given you're asking about C++11. That's all you need.
for emplace_back needn't move ctor and assigment, if enough memory already exists, so why I should defined them?
if the vector has to resize dynamically, it needs to move your already-emplaced items to a new allocated block.
Note that even if the move code is never called, it still needs to be instantiated. Even if the compiler is smart enough to analyze your run-time constraint at compile time, and optimize that code out, it still needs to be legally instantiatable.
|
1

Yes, you can put objects that aren't copyable or default-constructible in a vector in C++11, if they are movable:

#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); } 

But you can't use the constructor that fills such a vector with copies of a given value - since the values are not copyable. Similarly, you can't grow a vector of such objects with resize.

Comments

0

Write a move constructor and then use 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); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.