#include <deque>
#include <vector>
struct A
{
A(int* const p) : m_P(p) {}
A(A&& rhs) : m_P(rhs.m_P) { rhs.m_P = nullptr; }
A& operator=(A&& rhs) { delete m_P; m_P = rhs.m_P; rhs.m_P = nullptr; }
~A() { delete m_P; }
A(A const& rhs) = delete;
A& operator=(A const& rhs) = delete;
int* m_P;
};
int main()
{
#ifdef DDDEQUE
std::vector<std::pair<int, std::deque<A> > > vd;
vd.emplace(vd.end(), 1, std::deque<A>());
#endif // #ifdef DDDEQUE
std::vector<std::pair<int, std::vector<A> > > vv;
vv.emplace(vv.end(), 1, std::vector<A>());
}
If compiling with g++ 4.8.5, 5.2.0, 5.3.0 and -DDDDEQUE I get a verbose error message ending with
.../bits/stl_construct.h:75:7: error: use of deleted function ‘A::A(const A&)’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
^
gcc.cpp:11:5: note: declared here
A(A const& rhs) = delete;
without -D... compiles OK.
With VC2015, VC2012 both versions compile OK.
Does deque (but not vector) need the copy constructor for gcc?
This appears to be specific to libstdc++ (gcc); given the code below;
struct A
{
A() {};
A(A&&) noexcept { }
A& operator=(A&&) noexcept { return *this; }
~A() { }
};
int main()
{
std::vector<A> a;
a.push_back(A{}); // or emplace(a.end()... etc.
std::vector<std::deque<A>> b;
b.push_back(std::deque<A>());
std::vector<std::pair<int,A>> c;
c.push_back(std::pair<int,A>{});
std::vector<std::pair<int,std::deque<A>>> d;
d.push_back(std::pair<int,std::deque<A>>{});
}
G++ fails to compile b, and d, clang compiles all 4 (except possibly d depending on the version of libc++ used) and MSVC compiles all 4 cases (using their own associated standard library; with libstdc++, clang also fails b and d).
Does deque (but not vector) need the copy constructor for gcc?
It appears as though, yes gcc does still require the copy constructor.
In more formal terms; in C++03 std::deque required the type used in the container to be Copy Constructible and Copy Assignable. This changed in C++11, the requirements were relaxed, albeit a complete type is generally still required - given the OP sample, your standard library still requires the copy construction and assignment.
From the linked reference;
T - The type of the elements.
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)
Related
Consider the following code:
#include <variant>
#include <cassert>
struct foo {
foo() noexcept;
foo(const foo&) noexcept = default;
foo(foo&&) noexcept = default;
foo& operator=(const foo&) noexcept = default;
foo& operator=(foo&&) noexcept = default;
};
std::variant<std::monostate, foo> var;
foo::foo() noexcept {
assert(!var.valueless_by_exception());
};
int main() {
var.emplace<foo>();
}
With libstdc++ (from GCC 11), this works, but with libc++ (from LLVM 12), and MSVC, the assert fails.
Which standard library implements the correct behaviour ? At no point any exception is thrown, and my type is entirely noexcept, so I'd expect "valueless_from_exception" to never be true.
To quote the standard (https://timsong-cpp.github.io/cppwp/n4861/variant#status):
A variant might not hold a value if an exception is thrown during a type-changing assignment or emplacement.
here I am clearly not in that case.
The standard doesn't currently provide an answer to your question, but the direction that LWG appears to be moving in is that your code will have undefined behaviour.
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;
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;