我有以下代码:
#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()
为什么a.x.size()在&#34;部分I&#34;大小10?我认为std :: move应该将所有数据从a.x移动到y.x
为什么&#34;第二节&#34;调用构造函数A()两次?我认为B(const A&amp;&amp;)会阻止过度复制A
更新
处的固定代码答案 0 :(得分:4)
T&&
和const T&&
的类型不同。您几乎从不想要const
右值引用 - 自从您创建const
之后就无法窃取其资源!由于std::move(a.x)
的返回类型为x = std::move(a.x);
,B(const A&a)
a.x
const vector<int>&&
B(const A&&)
{/ 1}}。A
调用A
的默认构造函数,因为它是从A
派生的,并且成员初始值设定项列表不会尝试构造基础A
}。这是第二次{{1}}电话。 答案 1 :(得分:2)
为什么
a.x.size()
在&#34;部分I&#34;大小10?我认为std::move
应该将所有数据从a.x
移到y.x
这是因为B(const A&& a)
。由于该a
const
位于该构造函数中,因此您只有const
个成员x
的访问权限,而std::move
上的vector<T> const
调用结果为vector<T> const&&
一个vector
,它无法绑定到vector<T>&&
的移动构造函数(带有A()
参数)。相反,它最终会调用复制构造函数,这会使源对象保持不变。
为什么&#34;第二节&#34;调用构造函数
B(const A&&)
两次?我认为A
可以防止过度复制ret_a()
第一个默认构造发生在A
的主体内。第二个默认构造是B
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
的内容,因为用户提供的复制构造函数和析构函数定义会阻止隐式生成{{1}}的移动构造函数,并且它会被复制。