Does Visual Studio 2017 need an explicit move constructor declaration?
Clash Royale CLAN TAG#URR8PPP
up vote
11
down vote
favorite
The below code can be compiled successfully using Visual Studio 2015, but it failed using Visual Studio 2017. Visual Studio 2017 reports:
error C2280: “std::pair::pair(const std::pair &)â€Â: attempting to reference a deleted function
Code
#include <unordered_map>
#include <memory>
struct Node
std::unordered_map<int, std::unique_ptr<int>> map_;
// Uncommenting the following two lines will pass Visual Studio 2017 compilation
//Node(Node&& o) = default;
//Node() = default;
;
int main()
std::vector<Node> vec;
Node node;
vec.push_back(std::move(node));
return 0;
It looks like Visual Studio 2017 explicit needs a move constructor declaration. What is the reason?
c++ visual-studio-2017 move-constructor
New contributor
finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |Â
up vote
11
down vote
favorite
The below code can be compiled successfully using Visual Studio 2015, but it failed using Visual Studio 2017. Visual Studio 2017 reports:
error C2280: “std::pair::pair(const std::pair &)â€Â: attempting to reference a deleted function
Code
#include <unordered_map>
#include <memory>
struct Node
std::unordered_map<int, std::unique_ptr<int>> map_;
// Uncommenting the following two lines will pass Visual Studio 2017 compilation
//Node(Node&& o) = default;
//Node() = default;
;
int main()
std::vector<Node> vec;
Node node;
vec.push_back(std::move(node));
return 0;
It looks like Visual Studio 2017 explicit needs a move constructor declaration. What is the reason?
c++ visual-studio-2017 move-constructor
New contributor
finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
You're missing#include <vector>
but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?
– rubenvb
6 hours ago
I can confirm this code fails with error code under vs2017 15.4.2.
– marcinj
6 hours ago
add a comment |Â
up vote
11
down vote
favorite
up vote
11
down vote
favorite
The below code can be compiled successfully using Visual Studio 2015, but it failed using Visual Studio 2017. Visual Studio 2017 reports:
error C2280: “std::pair::pair(const std::pair &)â€Â: attempting to reference a deleted function
Code
#include <unordered_map>
#include <memory>
struct Node
std::unordered_map<int, std::unique_ptr<int>> map_;
// Uncommenting the following two lines will pass Visual Studio 2017 compilation
//Node(Node&& o) = default;
//Node() = default;
;
int main()
std::vector<Node> vec;
Node node;
vec.push_back(std::move(node));
return 0;
It looks like Visual Studio 2017 explicit needs a move constructor declaration. What is the reason?
c++ visual-studio-2017 move-constructor
New contributor
finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
The below code can be compiled successfully using Visual Studio 2015, but it failed using Visual Studio 2017. Visual Studio 2017 reports:
error C2280: “std::pair::pair(const std::pair &)â€Â: attempting to reference a deleted function
Code
#include <unordered_map>
#include <memory>
struct Node
std::unordered_map<int, std::unique_ptr<int>> map_;
// Uncommenting the following two lines will pass Visual Studio 2017 compilation
//Node(Node&& o) = default;
//Node() = default;
;
int main()
std::vector<Node> vec;
Node node;
vec.push_back(std::move(node));
return 0;
It looks like Visual Studio 2017 explicit needs a move constructor declaration. What is the reason?
c++ visual-studio-2017 move-constructor
c++ visual-studio-2017 move-constructor
New contributor
finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
edited 15 mins ago


Sombrero Chicken
22.3k32772
22.3k32772
New contributor
finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked 6 hours ago


finn
592
592
New contributor
finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
finn is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
You're missing#include <vector>
but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?
– rubenvb
6 hours ago
I can confirm this code fails with error code under vs2017 15.4.2.
– marcinj
6 hours ago
add a comment |Â
You're missing#include <vector>
but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?
– rubenvb
6 hours ago
I can confirm this code fails with error code under vs2017 15.4.2.
– marcinj
6 hours ago
You're missing
#include <vector>
but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?– rubenvb
6 hours ago
You're missing
#include <vector>
but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?– rubenvb
6 hours ago
I can confirm this code fails with error code under vs2017 15.4.2.
– marcinj
6 hours ago
I can confirm this code fails with error code under vs2017 15.4.2.
– marcinj
6 hours ago
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
7
down vote
Minimal example:
#include <memory>
#include <unordered_map>
#include <vector>
int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);
Live demo on GodBolt: https://godbolt.org/z/VApPkH.
Another example:
std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280
UPDATE
I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept
, therefore preferring copy constructors to throwing move constructors.
In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map
is (seemingly) noexcept
. Consequently, move constructor of Node
is noexcept
as well, and its copy constructor is not at all involved.
On the other hand, implementation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map
as noexcept
. Therefore, move constructor of Node
is not noexcept
as well, and vector's reallocation function via std::move_if_noexcept
tries to invoke copy constructor of Node
.
Copy constructor of Node
is implicitly defined such that is invokes copy constructor of std::unordered_map
. However, the latter may not be invoked here, since the value type of map (std::pair<const int, std::unique_ptr<int>>
in this case) is not copyable.
Finally, if you user-define move constructor of Node
, its implicitly declared copy constructor is defined as deleted. And, IIRC, deleted implicitly declared copy constructor does not participate in overload resolution. But, the deleted copy constructor is not considered by std::move_if_noexcept
, therefore it will use throwing move constructor of Node.
Is this realy a bug?std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>>
is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
– Oliv
2 hours ago
@Oliv That's a good question. It seems that the problem is that the move constructor ofstd::unordered_map
is notnoexcept
in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it isnoexcept
.
– Daniel Langr
1 hour ago
@Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
– Daniel Langr
1 hour ago
@Oliv Thanks for clarificaton, I rephrased my answer not to mention CopyInsertable requirement. Important is, thatstd::unordered_map
defines copy constructor, just it may not be invoked if the value type cannot be copied.
– Daniel Langr
1 hour ago
I think that we have excavated a rule to apply when we will use concepts. That is to make sure that the interface of a type really reflects its requirements. For example here the copy constructor of the unordered_map should have a constraintrequires is_copy_constructible_v<element_type>
or equivalent. I don't know how to name it, maybe rule concept propagation rule or maybe concept explicity rule ...??
– Oliv
3 mins ago
add a comment |Â
up vote
5
down vote
When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.
unique_ptr
is not CopyInsertable
in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_
is ill-formed (it could have been declared as deleted, but this is not required by the standard).
As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).
So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
– Oliv
3 hours ago
1
I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor ofstd::unordered_map
(and therefore ofNode
) is notnoexcept
? Then,push_back
, i.e.,emplace_back
, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept
)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
– Daniel Langr
3 hours ago
3
The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible withunordered_map
, and ended up having to use private inheritance fromstd::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type
whereAllowCopy
is empty andDisallowCopy
has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
– Arne Vogel
2 hours ago
2
is_nothrow_move_constructible_v<Node>
isfalse
in MSVC, so it tries to copy and fails; it istrue
in gcc, so it moves. Ifis_nothrow_move_constructible_v<Node>
is forced to becomefalse
in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree onis_nothrow_move_constructible_v<Node>
value?
– Evg
1 hour ago
 |Â
show 5 more comments
up vote
3
down vote
Let's look at the std::vector
source code (I replaced pointer
and _Ty
with actual types):
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);
If Node
is no-throw move-constructible or is not copy-constructible, _Uninitialized_move
is called, otherwise, _Uninitialized_copy
is called.
The problem is that the type trait std::is_copy_constructible_v
is true
for Node
if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.
libstdc++ implements std::vector
in a similar way, but there std::is_nothrow_move_constructible_v<Node>
is true
in contrast to MSVC, where it is false
. So, move semantics is used and the compiler does not try to generate the copy-constructor.
But if we force is_nothrow_move_constructible_v
to become false
struct Base
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;
struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;
int main()
std::vector<Node> vec;
vec.reserve(1);
the same error occurs:
/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune, the dumb answer is because gcc's and clang's implementations do not rely onstd::is_copy_constructible
in this particular piece of code. I don't have a better answer now.
– Evg
3 hours ago
If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
– darune
3 hours ago
@darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
– Evg
3 hours ago
@darune, added some info about in libstdc++.
– Evg
2 hours ago
add a comment |Â
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
7
down vote
Minimal example:
#include <memory>
#include <unordered_map>
#include <vector>
int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);
Live demo on GodBolt: https://godbolt.org/z/VApPkH.
Another example:
std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280
UPDATE
I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept
, therefore preferring copy constructors to throwing move constructors.
In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map
is (seemingly) noexcept
. Consequently, move constructor of Node
is noexcept
as well, and its copy constructor is not at all involved.
On the other hand, implementation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map
as noexcept
. Therefore, move constructor of Node
is not noexcept
as well, and vector's reallocation function via std::move_if_noexcept
tries to invoke copy constructor of Node
.
Copy constructor of Node
is implicitly defined such that is invokes copy constructor of std::unordered_map
. However, the latter may not be invoked here, since the value type of map (std::pair<const int, std::unique_ptr<int>>
in this case) is not copyable.
Finally, if you user-define move constructor of Node
, its implicitly declared copy constructor is defined as deleted. And, IIRC, deleted implicitly declared copy constructor does not participate in overload resolution. But, the deleted copy constructor is not considered by std::move_if_noexcept
, therefore it will use throwing move constructor of Node.
Is this realy a bug?std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>>
is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
– Oliv
2 hours ago
@Oliv That's a good question. It seems that the problem is that the move constructor ofstd::unordered_map
is notnoexcept
in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it isnoexcept
.
– Daniel Langr
1 hour ago
@Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
– Daniel Langr
1 hour ago
@Oliv Thanks for clarificaton, I rephrased my answer not to mention CopyInsertable requirement. Important is, thatstd::unordered_map
defines copy constructor, just it may not be invoked if the value type cannot be copied.
– Daniel Langr
1 hour ago
I think that we have excavated a rule to apply when we will use concepts. That is to make sure that the interface of a type really reflects its requirements. For example here the copy constructor of the unordered_map should have a constraintrequires is_copy_constructible_v<element_type>
or equivalent. I don't know how to name it, maybe rule concept propagation rule or maybe concept explicity rule ...??
– Oliv
3 mins ago
add a comment |Â
up vote
7
down vote
Minimal example:
#include <memory>
#include <unordered_map>
#include <vector>
int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);
Live demo on GodBolt: https://godbolt.org/z/VApPkH.
Another example:
std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280
UPDATE
I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept
, therefore preferring copy constructors to throwing move constructors.
In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map
is (seemingly) noexcept
. Consequently, move constructor of Node
is noexcept
as well, and its copy constructor is not at all involved.
On the other hand, implementation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map
as noexcept
. Therefore, move constructor of Node
is not noexcept
as well, and vector's reallocation function via std::move_if_noexcept
tries to invoke copy constructor of Node
.
Copy constructor of Node
is implicitly defined such that is invokes copy constructor of std::unordered_map
. However, the latter may not be invoked here, since the value type of map (std::pair<const int, std::unique_ptr<int>>
in this case) is not copyable.
Finally, if you user-define move constructor of Node
, its implicitly declared copy constructor is defined as deleted. And, IIRC, deleted implicitly declared copy constructor does not participate in overload resolution. But, the deleted copy constructor is not considered by std::move_if_noexcept
, therefore it will use throwing move constructor of Node.
Is this realy a bug?std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>>
is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
– Oliv
2 hours ago
@Oliv That's a good question. It seems that the problem is that the move constructor ofstd::unordered_map
is notnoexcept
in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it isnoexcept
.
– Daniel Langr
1 hour ago
@Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
– Daniel Langr
1 hour ago
@Oliv Thanks for clarificaton, I rephrased my answer not to mention CopyInsertable requirement. Important is, thatstd::unordered_map
defines copy constructor, just it may not be invoked if the value type cannot be copied.
– Daniel Langr
1 hour ago
I think that we have excavated a rule to apply when we will use concepts. That is to make sure that the interface of a type really reflects its requirements. For example here the copy constructor of the unordered_map should have a constraintrequires is_copy_constructible_v<element_type>
or equivalent. I don't know how to name it, maybe rule concept propagation rule or maybe concept explicity rule ...??
– Oliv
3 mins ago
add a comment |Â
up vote
7
down vote
up vote
7
down vote
Minimal example:
#include <memory>
#include <unordered_map>
#include <vector>
int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);
Live demo on GodBolt: https://godbolt.org/z/VApPkH.
Another example:
std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280
UPDATE
I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept
, therefore preferring copy constructors to throwing move constructors.
In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map
is (seemingly) noexcept
. Consequently, move constructor of Node
is noexcept
as well, and its copy constructor is not at all involved.
On the other hand, implementation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map
as noexcept
. Therefore, move constructor of Node
is not noexcept
as well, and vector's reallocation function via std::move_if_noexcept
tries to invoke copy constructor of Node
.
Copy constructor of Node
is implicitly defined such that is invokes copy constructor of std::unordered_map
. However, the latter may not be invoked here, since the value type of map (std::pair<const int, std::unique_ptr<int>>
in this case) is not copyable.
Finally, if you user-define move constructor of Node
, its implicitly declared copy constructor is defined as deleted. And, IIRC, deleted implicitly declared copy constructor does not participate in overload resolution. But, the deleted copy constructor is not considered by std::move_if_noexcept
, therefore it will use throwing move constructor of Node.
Minimal example:
#include <memory>
#include <unordered_map>
#include <vector>
int main()
std::vector<std::unordered_map<int, std::unique_ptr<int>>> vec;
vec.reserve(1);
Live demo on GodBolt: https://godbolt.org/z/VApPkH.
Another example:
std::unordered_map<int, std::unique_ptr<int>> m;
auto m2 = std::move(m); // ok
auto m3 = std::move_if_noexcept(m); // error C2280
UPDATE
I believe the compilation error is legal. Vector's reallocation function can transfer (contents of) elements by using std::move_if_noexcept
, therefore preferring copy constructors to throwing move constructors.
In libstdc++ (GCC) / libc++ (clang), move constructor of std::unordered_map
is (seemingly) noexcept
. Consequently, move constructor of Node
is noexcept
as well, and its copy constructor is not at all involved.
On the other hand, implementation from MSVC 2017 seemingly does not specify move constructor of std::unordered_map
as noexcept
. Therefore, move constructor of Node
is not noexcept
as well, and vector's reallocation function via std::move_if_noexcept
tries to invoke copy constructor of Node
.
Copy constructor of Node
is implicitly defined such that is invokes copy constructor of std::unordered_map
. However, the latter may not be invoked here, since the value type of map (std::pair<const int, std::unique_ptr<int>>
in this case) is not copyable.
Finally, if you user-define move constructor of Node
, its implicitly declared copy constructor is defined as deleted. And, IIRC, deleted implicitly declared copy constructor does not participate in overload resolution. But, the deleted copy constructor is not considered by std::move_if_noexcept
, therefore it will use throwing move constructor of Node.
edited 41 mins ago
answered 2 hours ago
Daniel Langr
6,0142243
6,0142243
Is this realy a bug?std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>>
is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
– Oliv
2 hours ago
@Oliv That's a good question. It seems that the problem is that the move constructor ofstd::unordered_map
is notnoexcept
in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it isnoexcept
.
– Daniel Langr
1 hour ago
@Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
– Daniel Langr
1 hour ago
@Oliv Thanks for clarificaton, I rephrased my answer not to mention CopyInsertable requirement. Important is, thatstd::unordered_map
defines copy constructor, just it may not be invoked if the value type cannot be copied.
– Daniel Langr
1 hour ago
I think that we have excavated a rule to apply when we will use concepts. That is to make sure that the interface of a type really reflects its requirements. For example here the copy constructor of the unordered_map should have a constraintrequires is_copy_constructible_v<element_type>
or equivalent. I don't know how to name it, maybe rule concept propagation rule or maybe concept explicity rule ...??
– Oliv
3 mins ago
add a comment |Â
Is this realy a bug?std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>>
is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.
– Oliv
2 hours ago
@Oliv That's a good question. It seems that the problem is that the move constructor ofstd::unordered_map
is notnoexcept
in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it isnoexcept
.
– Daniel Langr
1 hour ago
@Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
– Daniel Langr
1 hour ago
@Oliv Thanks for clarificaton, I rephrased my answer not to mention CopyInsertable requirement. Important is, thatstd::unordered_map
defines copy constructor, just it may not be invoked if the value type cannot be copied.
– Daniel Langr
1 hour ago
I think that we have excavated a rule to apply when we will use concepts. That is to make sure that the interface of a type really reflects its requirements. For example here the copy constructor of the unordered_map should have a constraintrequires is_copy_constructible_v<element_type>
or equivalent. I don't know how to name it, maybe rule concept propagation rule or maybe concept explicity rule ...??
– Oliv
3 mins ago
Is this realy a bug?
std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>>
is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.– Oliv
2 hours ago
Is this realy a bug?
std::is_copy_constructible_v<std::unordered_map<int, std::unique_ptr<int>>>
is true even if any attempt to copy such a type will result in a compilation error. Moreover it will also be detected as CopyInsertable, even if any try to instantiate the code to copy insert it will result in a compilation error.– Oliv
2 hours ago
@Oliv That's a good question. It seems that the problem is that the move constructor of
std::unordered_map
is not noexcept
in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it is noexcept
.– Daniel Langr
1 hour ago
@Oliv That's a good question. It seems that the problem is that the move constructor of
std::unordered_map
is not noexcept
in MSVC 2017 (which is seemingly not required by the Standard, or is it?). In libstdc++/libc++, it is noexcept
.– Daniel Langr
1 hour ago
@Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
– Daniel Langr
1 hour ago
@Oliv I updated my answer, I guess you are right. I even don't think now that it is "surprising".
– Daniel Langr
1 hour ago
@Oliv Thanks for clarificaton, I rephrased my answer not to mention CopyInsertable requirement. Important is, that
std::unordered_map
defines copy constructor, just it may not be invoked if the value type cannot be copied.– Daniel Langr
1 hour ago
@Oliv Thanks for clarificaton, I rephrased my answer not to mention CopyInsertable requirement. Important is, that
std::unordered_map
defines copy constructor, just it may not be invoked if the value type cannot be copied.– Daniel Langr
1 hour ago
I think that we have excavated a rule to apply when we will use concepts. That is to make sure that the interface of a type really reflects its requirements. For example here the copy constructor of the unordered_map should have a constraint
requires is_copy_constructible_v<element_type>
or equivalent. I don't know how to name it, maybe rule concept propagation rule or maybe concept explicity rule ...??– Oliv
3 mins ago
I think that we have excavated a rule to apply when we will use concepts. That is to make sure that the interface of a type really reflects its requirements. For example here the copy constructor of the unordered_map should have a constraint
requires is_copy_constructible_v<element_type>
or equivalent. I don't know how to name it, maybe rule concept propagation rule or maybe concept explicity rule ...??– Oliv
3 mins ago
add a comment |Â
up vote
5
down vote
When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.
unique_ptr
is not CopyInsertable
in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_
is ill-formed (it could have been declared as deleted, but this is not required by the standard).
As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).
So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
– Oliv
3 hours ago
1
I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor ofstd::unordered_map
(and therefore ofNode
) is notnoexcept
? Then,push_back
, i.e.,emplace_back
, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept
)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
– Daniel Langr
3 hours ago
3
The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible withunordered_map
, and ended up having to use private inheritance fromstd::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type
whereAllowCopy
is empty andDisallowCopy
has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
– Arne Vogel
2 hours ago
2
is_nothrow_move_constructible_v<Node>
isfalse
in MSVC, so it tries to copy and fails; it istrue
in gcc, so it moves. Ifis_nothrow_move_constructible_v<Node>
is forced to becomefalse
in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree onis_nothrow_move_constructible_v<Node>
value?
– Evg
1 hour ago
 |Â
show 5 more comments
up vote
5
down vote
When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.
unique_ptr
is not CopyInsertable
in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_
is ill-formed (it could have been declared as deleted, but this is not required by the standard).
As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).
So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
– Oliv
3 hours ago
1
I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor ofstd::unordered_map
(and therefore ofNode
) is notnoexcept
? Then,push_back
, i.e.,emplace_back
, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept
)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
– Daniel Langr
3 hours ago
3
The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible withunordered_map
, and ended up having to use private inheritance fromstd::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type
whereAllowCopy
is empty andDisallowCopy
has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
– Arne Vogel
2 hours ago
2
is_nothrow_move_constructible_v<Node>
isfalse
in MSVC, so it tries to copy and fails; it istrue
in gcc, so it moves. Ifis_nothrow_move_constructible_v<Node>
is forced to becomefalse
in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree onis_nothrow_move_constructible_v<Node>
value?
– Evg
1 hour ago
 |Â
show 5 more comments
up vote
5
down vote
up vote
5
down vote
When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.
unique_ptr
is not CopyInsertable
in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_
is ill-formed (it could have been declared as deleted, but this is not required by the standard).
As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).
So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.
When you declare a move constructor, the implicitly declared copy constructor is defined as deleted. On the other hand, when you don't declare a move constructor, the compiler implicitly defines the copy constructor when it need it. And this implicit definition is ill-formed.
unique_ptr
is not CopyInsertable
in a container that uses a standard allocator because it is not copy constructible so the copy constructor of map_
is ill-formed (it could have been declared as deleted, but this is not required by the standard).
As your example code show us, with newer version of MSVC, this ill-formed definition is generated with this example code. I do not think there is something in the standard that forbids it (even if this is realy surprising).
So you should indeed ensure that the copy constructor of Node is declared or implicitly defined as deleted.
edited 3 hours ago
answered 4 hours ago
Oliv
7,1381750
7,1381750
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
– Oliv
3 hours ago
1
I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor ofstd::unordered_map
(and therefore ofNode
) is notnoexcept
? Then,push_back
, i.e.,emplace_back
, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept
)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
– Daniel Langr
3 hours ago
3
The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible withunordered_map
, and ended up having to use private inheritance fromstd::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type
whereAllowCopy
is empty andDisallowCopy
has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
– Arne Vogel
2 hours ago
2
is_nothrow_move_constructible_v<Node>
isfalse
in MSVC, so it tries to copy and fails; it istrue
in gcc, so it moves. Ifis_nothrow_move_constructible_v<Node>
is forced to becomefalse
in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree onis_nothrow_move_constructible_v<Node>
value?
– Evg
1 hour ago
 |Â
show 5 more comments
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
– Oliv
3 hours ago
1
I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor ofstd::unordered_map
(and therefore ofNode
) is notnoexcept
? Then,push_back
, i.e.,emplace_back
, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept
)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.
– Daniel Langr
3 hours ago
3
The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible withunordered_map
, and ended up having to use private inheritance fromstd::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type
whereAllowCopy
is empty andDisallowCopy
has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.
– Arne Vogel
2 hours ago
2
is_nothrow_move_constructible_v<Node>
isfalse
in MSVC, so it tries to copy and fails; it istrue
in gcc, so it moves. Ifis_nothrow_move_constructible_v<Node>
is forced to becomefalse
in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree onis_nothrow_move_constructible_v<Node>
value?
– Evg
1 hour ago
1
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
1
@darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
– Oliv
3 hours ago
@darune I think the bug is in the standard requirement. If a standard type is not copy constructible it should be possible to check it with traits. But actually implementing such a requirement would be a real pain. I hope that with concepts this will be fixed.
– Oliv
3 hours ago
1
1
I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor of
std::unordered_map
(and therefore of Node
) is not noexcept
? Then, push_back
, i.e., emplace_back
, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept
)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.– Daniel Langr
3 hours ago
I don't have VS2017 accessible, but couldn't be the problem with that implicitly-declared move constructor of
std::unordered_map
(and therefore of Node
) is not noexcept
? Then, push_back
, i.e., emplace_back
, may prefer copy constructor (during reallocation) than potentially throwing move constructor (std::move_if_noexcept
)? With user-declared move constructor, the copy constructor is deleted, so throwing move constructor will be used.– Daniel Langr
3 hours ago
3
3
The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible with
unordered_map
, and ended up having to use private inheritance from std::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type
where AllowCopy
is empty and DisallowCopy
has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.– Arne Vogel
2 hours ago
The type traits magic to do this "correctly" is surprisingly complex. I implemented an open addressing hash map (and set) that is mostly API-compatible with
unordered_map
, and ended up having to use private inheritance from std::conditional<std::is_copy_constructible<...>::value && ..., AllowCopy, DisallowCopy>::type
where AllowCopy
is empty and DisallowCopy
has deleted copy operations (among other things). I also check for default c'tible allocator, and all of this is still not quite right, e.g. I support neither allocator propagation on copy nor copying of elements in the allocator.– Arne Vogel
2 hours ago
2
2
is_nothrow_move_constructible_v<Node>
is false
in MSVC, so it tries to copy and fails; it is true
in gcc, so it moves. If is_nothrow_move_constructible_v<Node>
is forced to become false
in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree on is_nothrow_move_constructible_v<Node>
value?– Evg
1 hour ago
is_nothrow_move_constructible_v<Node>
is false
in MSVC, so it tries to copy and fails; it is true
in gcc, so it moves. If is_nothrow_move_constructible_v<Node>
is forced to become false
in gcc, it also tries to copy and fails. Why do MSVC and gcc disagree on is_nothrow_move_constructible_v<Node>
value?– Evg
1 hour ago
 |Â
show 5 more comments
up vote
3
down vote
Let's look at the std::vector
source code (I replaced pointer
and _Ty
with actual types):
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);
If Node
is no-throw move-constructible or is not copy-constructible, _Uninitialized_move
is called, otherwise, _Uninitialized_copy
is called.
The problem is that the type trait std::is_copy_constructible_v
is true
for Node
if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.
libstdc++ implements std::vector
in a similar way, but there std::is_nothrow_move_constructible_v<Node>
is true
in contrast to MSVC, where it is false
. So, move semantics is used and the compiler does not try to generate the copy-constructor.
But if we force is_nothrow_move_constructible_v
to become false
struct Base
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;
struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;
int main()
std::vector<Node> vec;
vec.reserve(1);
the same error occurs:
/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune, the dumb answer is because gcc's and clang's implementations do not rely onstd::is_copy_constructible
in this particular piece of code. I don't have a better answer now.
– Evg
3 hours ago
If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
– darune
3 hours ago
@darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
– Evg
3 hours ago
@darune, added some info about in libstdc++.
– Evg
2 hours ago
add a comment |Â
up vote
3
down vote
Let's look at the std::vector
source code (I replaced pointer
and _Ty
with actual types):
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);
If Node
is no-throw move-constructible or is not copy-constructible, _Uninitialized_move
is called, otherwise, _Uninitialized_copy
is called.
The problem is that the type trait std::is_copy_constructible_v
is true
for Node
if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.
libstdc++ implements std::vector
in a similar way, but there std::is_nothrow_move_constructible_v<Node>
is true
in contrast to MSVC, where it is false
. So, move semantics is used and the compiler does not try to generate the copy-constructor.
But if we force is_nothrow_move_constructible_v
to become false
struct Base
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;
struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;
int main()
std::vector<Node> vec;
vec.reserve(1);
the same error occurs:
/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune, the dumb answer is because gcc's and clang's implementations do not rely onstd::is_copy_constructible
in this particular piece of code. I don't have a better answer now.
– Evg
3 hours ago
If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
– darune
3 hours ago
@darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
– Evg
3 hours ago
@darune, added some info about in libstdc++.
– Evg
2 hours ago
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Let's look at the std::vector
source code (I replaced pointer
and _Ty
with actual types):
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);
If Node
is no-throw move-constructible or is not copy-constructible, _Uninitialized_move
is called, otherwise, _Uninitialized_copy
is called.
The problem is that the type trait std::is_copy_constructible_v
is true
for Node
if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.
libstdc++ implements std::vector
in a similar way, but there std::is_nothrow_move_constructible_v<Node>
is true
in contrast to MSVC, where it is false
. So, move semantics is used and the compiler does not try to generate the copy-constructor.
But if we force is_nothrow_move_constructible_v
to become false
struct Base
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;
struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;
int main()
std::vector<Node> vec;
vec.reserve(1);
the same error occurs:
/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let's look at the std::vector
source code (I replaced pointer
and _Ty
with actual types):
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, true_type)
// move [First, Last) to raw Dest, using allocator
_Uninitialized_move(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept1(Node* First, Node* Last, Node* Dest, false_type)
// copy [First, Last) to raw Dest, using allocator
_Uninitialized_copy(First, Last, Dest, this->_Getal());
void _Umove_if_noexcept(Node* First, Node* Last, Node* Dest)
// move_if_noexcept [First, Last) to raw Dest, using allocator
_Umove_if_noexcept1(First, Last, Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<Node>, negation<is_copy_constructible<Node>>>>);
If Node
is no-throw move-constructible or is not copy-constructible, _Uninitialized_move
is called, otherwise, _Uninitialized_copy
is called.
The problem is that the type trait std::is_copy_constructible_v
is true
for Node
if you do not declare a move constructor explicitly. This declaration makes copy-constructor deleted.
libstdc++ implements std::vector
in a similar way, but there std::is_nothrow_move_constructible_v<Node>
is true
in contrast to MSVC, where it is false
. So, move semantics is used and the compiler does not try to generate the copy-constructor.
But if we force is_nothrow_move_constructible_v
to become false
struct Base
Base() = default;
Base(const S&) = default;
Base(Base&&) noexcept(false)
;
struct Node : Base
std::unordered_map<int, std::unique_ptr<int>> map;
;
int main()
std::vector<Node> vec;
vec.reserve(1);
the same error occurs:
/usr/include/c++/7/ext/new_allocator.h:136:4: error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&) [with _T1 = const int; _T2 = std::unique_ptr<int>]’
::new((void *)__p) _Up(std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
edited 2 hours ago
answered 4 hours ago


Evg
3,42811334
3,42811334
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune, the dumb answer is because gcc's and clang's implementations do not rely onstd::is_copy_constructible
in this particular piece of code. I don't have a better answer now.
– Evg
3 hours ago
If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
– darune
3 hours ago
@darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
– Evg
3 hours ago
@darune, added some info about in libstdc++.
– Evg
2 hours ago
add a comment |Â
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
@darune, the dumb answer is because gcc's and clang's implementations do not rely onstd::is_copy_constructible
in this particular piece of code. I don't have a better answer now.
– Evg
3 hours ago
If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
– darune
3 hours ago
@darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
– Evg
3 hours ago
@darune, added some info about in libstdc++.
– Evg
2 hours ago
1
1
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
Im wondering as to why the issue is not seen with clang or gcc ?
– darune
4 hours ago
1
1
@darune, the dumb answer is because gcc's and clang's implementations do not rely on
std::is_copy_constructible
in this particular piece of code. I don't have a better answer now.– Evg
3 hours ago
@darune, the dumb answer is because gcc's and clang's implementations do not rely on
std::is_copy_constructible
in this particular piece of code. I don't have a better answer now.– Evg
3 hours ago
If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
– darune
3 hours ago
If i understand you correctly that code is in the MSVC vector implementation (?) and isn't that a bug in this case ? It does feel like like a bug, because invoking the move constructor directly does compile fine.
– darune
3 hours ago
@darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
– Evg
3 hours ago
@darune, yes, the code in my answer is directly from MSVC STL implementation. I agree that it feels like a bug.
– Evg
3 hours ago
@darune, added some info about in libstdc++.
– Evg
2 hours ago
@darune, added some info about in libstdc++.
– Evg
2 hours ago
add a comment |Â
finn is a new contributor. Be nice, and check out our Code of Conduct.
finn is a new contributor. Be nice, and check out our Code of Conduct.
finn is a new contributor. Be nice, and check out our Code of Conduct.
finn is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53168836%2fdoes-visual-studio-2017-need-an-explicit-move-constructor-declaration%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
You're missing
#include <vector>
but as far as I can tell, that code should compile (and it does on e.g. GCC 8.2). Do you have the latest and greatest VS2017?– rubenvb
6 hours ago
I can confirm this code fails with error code under vs2017 15.4.2.
– marcinj
6 hours ago