使用 std::move 来防止复制
using std::move to prevent copying
我有以下代码:
#include <iostream>
#include <vector>
struct A
{
std::vector<int> x;
A()
{
std::cout << "A()" << std::endl;
}
A(const A&)
{
std::cout << "A(const A&)" << std::endl;
}
~A()
{
std::cout << "~A()" << std::endl;
}
};
struct B : public A
{
std::vector<int> y;
B()
{
std::cout << "B()" << std::endl;
}
B(const A&a)
{
std::cout << "B(const A&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const A&&a)
{
std::cout << "B(const A&&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const B&)
{
std::cout << "B(const B&)" << std::endl;
}
~B()
{
std::cout << "~B()" << std::endl;
}
};
A ret_a()
{
A a;
a.x.resize(10);
return a;
}
int main()
{
std::cout << "section I" << std::endl << std::endl;
A a = ret_a();
B b(a);
std::cout << "a.x.size=" << a.x.size() << std::endl;
std::cout << std::endl << "section II" << std::endl << std::endl;
B b2(ret_a());
std::cout << "b.x.size=" << b.x.size() << std::endl;
std::cout << std::endl << "section III" << std::endl << std::endl;
return 0;
}
有输出(VS2013,发布版本)
section I
A()
A()
B(const A&)
a.x.size=10
section II
A()
A()
B(const A&&)
~A()
b.x.size=10
section III
~B()
~A()
~B()
~A()
~A()
为什么 "section I" 中的 a.x.size() 大小为 10?我认为 std::move 应该将所有数据从 a.x 移动到 y.x
为什么 "section II" 调用构造函数 A() 两次?我认为 B(const A&&) 会防止过度复制 A
更新
处的固定代码
T&&
和 const T&&
不是同一类型。您几乎永远不需要 const
右值引用 - 自从您创建 const
后就无法窃取它的资源! B(const A&a)
中的 x = std::move(a.x);
复制 a.x
因为 std::move(a.x)
的 return 类型是 const vector<int>&&
.
- 构造函数
B(const A&&)
调用 A
的默认构造函数,因为它派生自 A
,并且成员初始值设定项列表不会尝试构造基础 A
。这是第二次 A
调用。
Why a.x.size()
within "section I" has size 10? I thought that std::move
should move all data from a.x
to y.x
这是因为 B(const A&& a)
。由于 a
在该构造函数中是 const
,因此您只能 const
访问其成员 x
,并且在 vector<T> const
上调用 std::move
会导致vector<T> const&&
无法绑定到 vector
的移动构造函数(它采用 vector<T>&&
参数)。相反,它最终会调用复制构造函数,这会使源对象保持不变。
Why did "section II" call constructor A()
twice? I thought that B(const A&&)
would prevent excessive copying of A
第一个默认构造发生在 ret_a()
的正文中。第二个默认构造是 B
的 A
子对象。为了避免第二个 move
成员初始值设定项列表中的 A
实例。
B(const A&&a)
: A(std::move(a))
{
std::cout << "B(const A&&)" << std::endl;
y.resize(x.size());
}
请注意,由于与上述相同的原因,move
实际上不会导致移动 a
的内容。此外,即使将签名修改为 B(A&& a)
也不会导致 a
的内容被移动,因为用户提供的复制构造函数和析构函数定义阻止了为 A
隐式生成移动构造函数,并且它将被复制。
我有以下代码:
#include <iostream>
#include <vector>
struct A
{
std::vector<int> x;
A()
{
std::cout << "A()" << std::endl;
}
A(const A&)
{
std::cout << "A(const A&)" << std::endl;
}
~A()
{
std::cout << "~A()" << std::endl;
}
};
struct B : public A
{
std::vector<int> y;
B()
{
std::cout << "B()" << std::endl;
}
B(const A&a)
{
std::cout << "B(const A&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const A&&a)
{
std::cout << "B(const A&&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const B&)
{
std::cout << "B(const B&)" << std::endl;
}
~B()
{
std::cout << "~B()" << std::endl;
}
};
A ret_a()
{
A a;
a.x.resize(10);
return a;
}
int main()
{
std::cout << "section I" << std::endl << std::endl;
A a = ret_a();
B b(a);
std::cout << "a.x.size=" << a.x.size() << std::endl;
std::cout << std::endl << "section II" << std::endl << std::endl;
B b2(ret_a());
std::cout << "b.x.size=" << b.x.size() << std::endl;
std::cout << std::endl << "section III" << std::endl << std::endl;
return 0;
}
有输出(VS2013,发布版本)
section I
A()
A()
B(const A&)
a.x.size=10
section II
A()
A()
B(const A&&)
~A()
b.x.size=10
section III
~B()
~A()
~B()
~A()
~A()
为什么 "section I" 中的 a.x.size() 大小为 10?我认为 std::move 应该将所有数据从 a.x 移动到 y.x
为什么 "section II" 调用构造函数 A() 两次?我认为 B(const A&&) 会防止过度复制 A
更新
处的固定代码T&&
和const T&&
不是同一类型。您几乎永远不需要const
右值引用 - 自从您创建const
后就无法窃取它的资源!B(const A&a)
中的x = std::move(a.x);
复制a.x
因为std::move(a.x)
的 return 类型是const vector<int>&&
.- 构造函数
B(const A&&)
调用A
的默认构造函数,因为它派生自A
,并且成员初始值设定项列表不会尝试构造基础A
。这是第二次A
调用。
Why
a.x.size()
within "section I" has size 10? I thought thatstd::move
should move all data froma.x
toy.x
这是因为 B(const A&& a)
。由于 a
在该构造函数中是 const
,因此您只能 const
访问其成员 x
,并且在 vector<T> const
上调用 std::move
会导致vector<T> const&&
无法绑定到 vector
的移动构造函数(它采用 vector<T>&&
参数)。相反,它最终会调用复制构造函数,这会使源对象保持不变。
Why did "section II" call constructor
A()
twice? I thought thatB(const A&&)
would prevent excessive copying ofA
第一个默认构造发生在 ret_a()
的正文中。第二个默认构造是 B
的 A
子对象。为了避免第二个 move
成员初始值设定项列表中的 A
实例。
B(const A&&a)
: A(std::move(a))
{
std::cout << "B(const A&&)" << std::endl;
y.resize(x.size());
}
请注意,由于与上述相同的原因,move
实际上不会导致移动 a
的内容。此外,即使将签名修改为 B(A&& a)
也不会导致 a
的内容被移动,因为用户提供的复制构造函数和析构函数定义阻止了为 A
隐式生成移动构造函数,并且它将被复制。