Visual Studio 2017是否需要显式的move构造函数声明? [英] Does Visual Studio 2017 need an explicit move constructor declaration?
问题描述
以下代码可以使用Visual Studio 2015成功编译,但是使用Visual Studio 2017则失败.VisualStudio 2017报告:
The below code can be compiled successfully using Visual Studio 2015, but it failed using Visual Studio 2017. Visual Studio 2017 reports:
错误C2280:"std :: pair :: pair(const std :: pair&)":试图引用已删除的函数
error C2280: "std::pair::pair(const std::pair &)": attempting to reference a deleted function
代码
#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;
}
看起来Visual Studio 2017显式需要移动构造函数声明.是什么原因?
It looks like Visual Studio 2017 explicit needs a move constructor declaration. What is the reason?
推荐答案
让我们看一下 std :: vector
源代码(我替换了 pointer
和 _Ty
(带有实际类型):
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>>>>{});
}
如果 Node
是无掷移动可构造或不可复制构造,则调用 _Uninitialized_move
,否则将调用 _Uninitialized_copy
.
If Node
is no-throw move-constructible or is not copy-constructible, _Uninitialized_move
is called, otherwise, _Uninitialized_copy
is called.
问题在于,如果您未显式声明移动构造函数,则类型特征 std :: is_copy_constructible_v
对于 Node
来说是 true
.该声明使复制构造函数被删除.
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 ++以类似的方式实现 std :: vector
,但是与MSVC相比, std :: is_nothrow_move_constructible_v< Node>
是 true
,它是 false
.因此,使用了移动语义,并且编译器不会尝试生成复制构造函数.
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.
但是如果我们强制 is_nothrow_move_constructible_v
变为 false
But if we force is_nothrow_move_constructible_v
to become false
struct Base {
Base() = default;
Base(const Base&) = 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);
}
发生相同的错误:
/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)...); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
这篇关于Visual Studio 2017是否需要显式的move构造函数声明?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!