This is a demo class. I do not want my class to be copied, so I delete the copy constructor. I want vector.emplace_back to use this constructor 'MyClass(Type type)'. But these codes won't compile. Why?
class MyClass
{
public:
typedef enum
{
e1,
e2
} Type;
private:
Type _type;
MyClass(const MyClass& other) = delete; // no copy
public:
MyClass(): _type(e1) {};
MyClass(Type type): _type(type) { /* the constructor I wanted. */ };
};
std::vector<MyClass> list;
list.emplace_back(MyClass::e1);
list.emplace_back(MyClass::e2);
The copy constructor is required by vector so that it can copy the element when it need to grow its storage.
You can read the document for vector
T must meet the requirements of CopyAssignable and
CopyConstructible. (until C++11)
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. (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 meets the requirements of Erasable, but many member
functions impose stricter requirements. This container (but not its
members) can be instantiated with an incomplete element type if the
allocator satisfies the allocator completeness requirements.
Some logging can help you understand what's going on
For this code
class MyClass
{
public:
typedef enum
{
e1 = 1,
e2 = 2,
e3 = 3,
} Type;
private:
Type _type;
public:
MyClass(Type type): _type(type) { std::cout << "create " << type << "\n"; };
MyClass(const MyClass& other) { std::cout << "copy " << other._type << "\n"; }
};
int main() {
std::vector<MyClass> list;
list.reserve(2);
list.emplace_back(MyClass::e1);
list.emplace_back(MyClass::e2);
list.emplace_back(MyClass::e3);
}
The output is
create 1
create 2
create 3
copy 1
copy 2
So you can emplace_back does use the desired constructor to create the element and call copy constructor when it need to grow the storage. You can call reserve with enough capacity upfront to avoid the need to call copy constructor.
If for some reason you really don't want it to be copy constructible, you can use std::list instead of std::vector as list is implemented as linked list, it doesn't need to move the elements.
http://coliru.stacked-crooked.com/a/16f93cfc6b2fc73c
Just a precision for the issue. If we don't want objects copy construction to be used when a reallocation of the container occurs, it is indeed possible with a move constructor but only if it has the noexcept specification.
Containers refuse to move construct elements if the constructor might throw an exception because it could lead to a container in a bad state that cannot be cleaned. That's the reason why it is generally a good practice to specify a move constructor as noexcept when we are sure it will never throw any exceptions.
According to https://en.cppreference.com/w/cpp/container/vector/emplace_back, the value_type of a std::vector<T> needs to be MoveInsertable and EmplaceConstructible. MoveInsertable in particular requires a move constructor or a copy constructor.
So, if you don't want your class to be copied, you should add an explicit move constructor. You can use = default to use the compiler-provided default implementation that just moves all fields.
Full example
#include <vector>
class MyClass
{
public:
typedef enum
{
e1,
e2
} Type;
private:
Type _type;
MyClass(const MyClass& other) = delete; // no copy
public:
MyClass(): _type(e1) {};
MyClass(MyClass&&) noexcept = default; // < the new move constructor
MyClass(Type type): _type(type) { /* the constructor I wanted. */ };
};
int main() {
std::vector<MyClass> list;
list.emplace_back(MyClass::e1);
list.emplace_back(MyClass::e2);
}
Note
Note that you can get a very confusing
error: use of deleted function ‘MyClass::MyClass(const MyClass&)
with C++17 when you use
auto x = list.emplace_back(MyClass::e1);
instead of
auto& x = list.emplace_back(MyClass::e1);
even with the move constructor.
Related
In the following code , I am not able to understand why the destructor of the class Buf is invoked twice. When debugging I can see that it is being invoked the first time when the running thread is leaving the function Test::produce. The second time is when leaving the main function which essentially is when destructing the class EventQueue, something I would expect.
However, I dont understand why when leaving the function Test::produce the destructor of Buf is invoked. Specifically, I create the class Buf as a r-value passing it to the EventQueue and move to its internal cache. In fact, this has created me the problem that I end up trying ti free the same pointer twice which throws an exception.
template<typename T>
class EventQueue{
public:
void offer(T&& t) {
m_queue.try_emplace(std::this_thread::get_id()).first->second.push(std::move(t));
};
std::unordered_map<std::thread::id, std::queue<T>> m_queue;
};
class Buf{
const uint8_t *m_data;
const size_t m_size;
public:
Buf(const uint8_t *data, size_t size) : m_data(data), m_size(size) { }
size_t size() const { return m_size; }
const uint8_t *data() const { return m_data; }
~Buf()
{
std::cout << "dtor called " << std::endl;
free((void *)m_data);
}
};
class Test{ and was not expecting
public:
Test(shared_ptr<EventQueue<Buf>> buf) : m_buf(buf)
{
std::thread t1 = std::thread([this] { this->produce(10); });
t1.detach();
};
void produce(int msg_size) {
m_buf->offer(Buf(new uint8_t[msg_size], 10));
}
std::shared_ptr<EventQueue<Buf>> m_buf;
};
int main()
{
auto event_queue = std::make_shared<EventQueue<Buf>>();
Test tt(event_queue);
return 0;
}
The destructor is called two times because you have two objects to destroy. First - the temporary you created as an argument for the offer function parameter:
void produce(int msg_size) {
m_buf->offer(Buf(new uint8_t[msg_size], 10));
}
Second - when you add this temporary to std::queue container, it makes a copy under the hood:
void offer(T&& t) {
m_queue.try_emplace(std::this_thread::get_id()).first->second.push(std::move(t));
};
Every temporary object created must always be destructed. However the problem is not about how many objects were destructed, but that you ignore the rules of zero, three and five here. I.e. if you create any of a destructor, a copy constructor or a copy-assignment operator, you are supposed to take care of all three. Another side effect is that the compiler will not generate the move constructor and move assignment operator for you when any of the big three are explicitly defined. Thus, when passing rvalue-reference to a Buf constructor, you actually ends up with a copy constructor.
However even if it was a default move constructor, it would not solve your problem, because resources represented with raw pointers which your class instance "owns" (and is supposed to delete at some point) are not quite compatible with the implicit move constructor, which merely does member-wise std::move:
For non-union class types (class and struct), the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument.
For any built-in types (including raw pointers), it means that nothing actually happens and they are just copied.
Long story short: you have to nullify the source object's member raw pointer explicitly:
Buf(Buf&& other) noexcept : m_data{ std::exchange(other.m_data, nullptr) }, m_size{ other.m_size } {}
The better solution would be to not mess with rules of three/five and stick to rule of zero, by leveraging RAII idiom and letting automatic storage duration to handle the resources without explicitly allocating/releasing them:
class Buf{
const std::vector<std::uint8_t> m_data;
public:
Buf(std::vector<std::uint8_t> data) : m_data{ std::move(data) } { }
const std::vector<std::uint8_t>& data() const {
return m_data;
}
};
I want to define a move constructor on a class that will be instantiated in a std::vector. However, the move constructor seems to interfere with the initialization of the vector.
#include <iostream>
#include <vector>
class cell
{
private:
int m_value;
public:
void clear() {m_value = 0;}
cell(int i = 0): m_value(i) {}
cell(const cell&& move): m_value(move.m_value) {} //move constructor
cell& operator= (const cell& copy)
{
if (© == this) return *this;
clear();
m_value = copy.m_value;
return *this;
}
int getValue() const {return m_value;}
};
int main()
{
cell mycell {3}; // initializes correctly
std::vector<cell> myVec {1, 2, 3, 4}; // compile error.
return 0;
}
I have done quite a bit of research but haven't been able to find the solution to this problem. Quite new to C++ programming.
edit: my class will eventually have a lot more than m_value in it, including some non-fundamental types, hence I don't want to use the default copy constructor.
The problem is that in std::vector constructor with parametr of type std::initializer_list elements are copy-initialized, therefore, copy constructor is requried for your cell class (see, e.g., Why copy constructor is called in std::vector's initializer list? for some relevant discussion). Otherwise, you would be fine with move constructor:
std::vector<cell> myVec;
myVec.push_back(1);
...
cell(const cell&& move): m_value(move.m_value) {}
Is wrong in several ways. First, the const means that it applies to a move from const objects. This is rarely what you want.
edit: The const move-constructor does not overcome the constness of the std::initializer_list objects, since the vector constructor never moves elements from the initializer_list regardless of the avialability of a const move constructor.
Second, it should have a noexcept specifier, otherwise the vector will prefer not to use the move constructor when it increases capacity. To have it work, you should replace the code with:
cell(cell&& move) noexcept: m_value(move.m_value) {}
Third, it is better to use the default, when possible:
cell(cell&& move) noexcept = default;
I have a std::vector of objects of a certain class A. The class is non-trivial and has copy constructors and move constructors defined.
std::vector<A> myvec;
If I fill-up the vector with A objects (using e.g. myvec.push_back(a)), the vector will grow in size, using the copy constructor A( const A&) to instantiate new copies of the elements in the vector.
Can I somehow enforce that the move constructor of class A is beging used instead?
You need to inform C++ (specifically std::vector) that your move constructor and destructor does not throw, using noexcept. Then the move constructor will be called when the vector grows.
This is how to declare and implement a move constuctor that is respected by std::vector:
A(A && rhs) noexcept {
std::cout << "i am the move constr" <<std::endl;
... some code doing the move ...
m_value=std::move(rhs.m_value) ; // etc...
}
If the constructor is not noexcept, std::vector can't use it, since then it can't ensure the exception guarantees demanded by the standard.
For more about what's said in the standard, read
C++ Move semantics and Exceptions
Credit to Bo who hinted that it may have to do with exceptions. Also consider Kerrek SB's advice and use emplace_back when possible. It can be faster (but often is not), it can be clearer and more compact, but there are also some pitfalls (especially with non-explicit constructors).
Edit, often the default is what you want: move everything that can be moved, copy the rest. To explicitly ask for that, write
A(A && rhs) = default;
Doing that, you will get noexcept when possible: Is the default Move constructor defined as noexcept?
Note that early versions of Visual Studio 2015 and older did not support that, even though it supports move semantics.
Interestingly, gcc 4.7.2's vector only uses move constructor if both the move constructor and the destructor are noexcept. A simple example:
struct foo {
foo() {}
foo( const foo & ) noexcept { std::cout << "copy\n"; }
foo( foo && ) noexcept { std::cout << "move\n"; }
~foo() noexcept {}
};
int main() {
std::vector< foo > v;
for ( int i = 0; i < 3; ++i ) v.emplace_back();
}
This outputs the expected:
move
move
move
However, when I remove noexcept from ~foo(), the result is different:
copy
copy
copy
I guess this also answers this question.
It seems, that the only way (for C++17 and early), to enforce std::vector use move semantics on reallocation is deleting copy constructor :) . In this way it will use your move constructors or die trying, at compile time :).
There are many rules where std::vector MUST NOT use move constructor on reallocation, but nothing about where it MUST USE it.
template<class T>
class move_only : public T{
public:
move_only(){}
move_only(const move_only&) = delete;
move_only(move_only&&) noexcept {};
~move_only() noexcept {};
using T::T;
};
Live
or
template<class T>
struct move_only{
T value;
template<class Arg, class ...Args, typename = std::enable_if_t<
!std::is_same_v<move_only<T>&&, Arg >
&& !std::is_same_v<const move_only<T>&, Arg >
>>
move_only(Arg&& arg, Args&&... args)
:value(std::forward<Arg>(arg), std::forward<Args>(args)...)
{}
move_only(){}
move_only(const move_only&) = delete;
move_only(move_only&& other) noexcept : value(std::move(other.value)) {};
~move_only() noexcept {};
};
Live code
Your T class must have noexcept move constructor/assigment operator and noexcept destructor. Otherwise you'll get compilation error.
std::vector<move_only<MyClass>> vec;
I have a std::vector of objects of a certain class A. The class is non-trivial and has copy constructors and move constructors defined.
std::vector<A> myvec;
If I fill-up the vector with A objects (using e.g. myvec.push_back(a)), the vector will grow in size, using the copy constructor A( const A&) to instantiate new copies of the elements in the vector.
Can I somehow enforce that the move constructor of class A is beging used instead?
You need to inform C++ (specifically std::vector) that your move constructor and destructor does not throw, using noexcept. Then the move constructor will be called when the vector grows.
This is how to declare and implement a move constuctor that is respected by std::vector:
A(A && rhs) noexcept {
std::cout << "i am the move constr" <<std::endl;
... some code doing the move ...
m_value=std::move(rhs.m_value) ; // etc...
}
If the constructor is not noexcept, std::vector can't use it, since then it can't ensure the exception guarantees demanded by the standard.
For more about what's said in the standard, read
C++ Move semantics and Exceptions
Credit to Bo who hinted that it may have to do with exceptions. Also consider Kerrek SB's advice and use emplace_back when possible. It can be faster (but often is not), it can be clearer and more compact, but there are also some pitfalls (especially with non-explicit constructors).
Edit, often the default is what you want: move everything that can be moved, copy the rest. To explicitly ask for that, write
A(A && rhs) = default;
Doing that, you will get noexcept when possible: Is the default Move constructor defined as noexcept?
Note that early versions of Visual Studio 2015 and older did not support that, even though it supports move semantics.
Interestingly, gcc 4.7.2's vector only uses move constructor if both the move constructor and the destructor are noexcept. A simple example:
struct foo {
foo() {}
foo( const foo & ) noexcept { std::cout << "copy\n"; }
foo( foo && ) noexcept { std::cout << "move\n"; }
~foo() noexcept {}
};
int main() {
std::vector< foo > v;
for ( int i = 0; i < 3; ++i ) v.emplace_back();
}
This outputs the expected:
move
move
move
However, when I remove noexcept from ~foo(), the result is different:
copy
copy
copy
I guess this also answers this question.
It seems, that the only way (for C++17 and early), to enforce std::vector use move semantics on reallocation is deleting copy constructor :) . In this way it will use your move constructors or die trying, at compile time :).
There are many rules where std::vector MUST NOT use move constructor on reallocation, but nothing about where it MUST USE it.
template<class T>
class move_only : public T{
public:
move_only(){}
move_only(const move_only&) = delete;
move_only(move_only&&) noexcept {};
~move_only() noexcept {};
using T::T;
};
Live
or
template<class T>
struct move_only{
T value;
template<class Arg, class ...Args, typename = std::enable_if_t<
!std::is_same_v<move_only<T>&&, Arg >
&& !std::is_same_v<const move_only<T>&, Arg >
>>
move_only(Arg&& arg, Args&&... args)
:value(std::forward<Arg>(arg), std::forward<Args>(args)...)
{}
move_only(){}
move_only(const move_only&) = delete;
move_only(move_only&& other) noexcept : value(std::move(other.value)) {};
~move_only() noexcept {};
};
Live code
Your T class must have noexcept move constructor/assigment operator and noexcept destructor. Otherwise you'll get compilation error.
std::vector<move_only<MyClass>> vec;
Disclaimer
I'm trying to allocate an array of objects that are neither copy constructible, assignable nor has a default constructor. The objects have arguments that are determined at run time. I know that you can solve this problem by having an array of pointers or cleverly using placement new but I'm more interested in if this is possible to do cleanly with C++11 (1y) magic. So please, this is purely of theoretical interest so avoid trying to solve "my problem" by offering a work around.
The code...
...So the question is: Is there a way to make the following work in C++11 or C++14:
class X{
public:
explicit X(int a){...}
X(const X&) = delete;
void operator = (const X&) = delete;
private:
...
};
class Y{
public:
Y(const std::vector<int>& args) {
x = new X[]{args};
}
~Y(){
delete [] x;
}
private:
X* x;
};
Criteria
Specifically I'm looking for a solution/construct that meets the following criteria:
X is not copy constructible.
X is not assignable.
X does not have a default no-argument constructor (construction has intended side-effects).
The arguments to X's constructor are not known until run time.
All instances of X must be laid out contiguously in memory.
X must be properly destructed when the array is deleted from it's base pointer (or if an intermediate class is used, when the intermediate object is destructed). This rules out array of pointers and naivë use of placement new.
Edit / Addendum
I forgot to mention that move constructor is not available. In the actual case at hand, X spawns a worker thread and is executing in the context of this of the initially constructed object, any attempt to use a move constructor will corrupt the state of the executing thread.
You can use std::vector and its emplace_back function if you make X at least movable.
class X{
public:
explicit X(int){}
X(X&&) = default;
X(const X&) = delete;
void operator = (const X&) = delete;
};
int main() {
std::vector<X> xs;
xs.emplace_back(0);
xs.emplace_back(1);
xs.emplace_back(2);
xs.emplace_back(3);
}
(If you declare a copy constructor, even if that declaration deletes it, the compiler will not automatically generate any special move member, so you need to explicitly request them)
This basically boils down to the "array with placement new" strategy, but all abstracted away into high-level notions.
If you cannot make use of a movable type, you have to implement a vector-like class that pre-allocates storage and never reallocates. There is nothing similar in the standard library.
You're going to have to keep track of the constructed elements by hand, but you can use allocator to help:
class Y{
public:
Y(const std::vector<int>& args):
alloc{},
n{args.size()},
x{alloc.allocate(n)}
{
auto end = x;
try {
for (auto arg: args)
alloc.construct(end++, arg);
} catch (...) {
while (end != x)
alloc.destroy(--end);
alloc.deallocate(x, n);
throw;
}
}
~Y() {
for (auto end = std::next(x, n); end != x; --end)
alloc.destroy(end);
alloc.deallocate(x, n);
}
private:
std::allocator<X> alloc;
const std::size_t n;
const X *x;
};
A class that is neither copyable nor movable, nor has a default constructor, cannot be held in a standard container (doesn't meet the requirements) or a variable-sized array allocation (which only allows argument specification for a fixed number of elements).
This means you need to allocate raw memory instead and use placement new to construct the objects. You can wrap this in a fixed-space vector class.
template <typename T>
class fixed_capacity_vector {
public:
using size_type = std::size_t;
fixed_capacity_vector(size_type capacity)
: data_(::operator new(capacity * sizeof(T)), size_(), capacity_(capacity)
{}
fixed_capacity_vector(const fixed_capacity_vector&) = delete;
fixed_capacity_vector(fixed_capacity_vector&&) = delete;
fixed_capacity_vector& operator =(const fixed_capacity_vector&) = delete;
fixed_capacity_vector& operator =(fixed_capacity_vector&&) = delete;
~fixed_capacity_vector() {
for (size_type i = 0; i < size_; ++i) data_[i].~T();
::operator delete(data_);
}
template <typename... Args>
T& emplace_back(Args&&... args) {
if (size_ == capacity_) throw out_of_range();
new (data_ + size_) T(std::forward<Args>(args)...);
++size_;
return data_[size_-1];
}
private:
T* data_;
size_type size_;
size_type capacity_;
};