std::vector 的 c++ 复制构造函数与移动构造函数
c++ copy constructor vs move constructor for std::vector
我有一个 class,里面有一个 std::vector
像
struct Mystruct
{
Mystruct(const std::vector<int>& w): v(w)
{
std::cout << "Copy constructor :" << v.at(0) << "\n";
}
Mystruct(const std::vector<int>&& w): v(w)
{
std::cout << "Move Constructor :" << v.at(0) << "\n";
}
private:
std::vector<int> v;
};
然后我创建了像
这样的对象
int main()
{
auto x = std::vector<int> {1,2,3};
Mystruct M1(x);
Mystruct M2(std::vector<int> {3,2,1});
return 0;
}
M1
是使用复制构造函数构造的,M2
是使用"move"构造函数构造的,但是在gdb中运行两个赋值都为v和w保留了不同的地址,如果我在第二个构造函数的初始化列表中使用 v (std::move(w)),也会发生同样的情况。所以我猜这两个赋值都在复制 w 的内容,这是正确的吗?如果是这样,我怎样才能移动 w 的内容而不是复制它们
首先,移动对象不会改变它的地址。根据定义,您不能更改对象的地址,因为地址是对象定义的一部分。如果你有一个不同的地址,你有一个不同的对象。移动的作用(至少就标准库中的 类 而言)是转移对象动态分配资源的所有权。
其次,你没有移动任何东西。为了移动某些东西,你必须调用移动构造函数。这意味着您需要传递一个 r 值。命名对象永远不是右值。所以即使你有一个 r 值引用,你仍然需要用 std::move
来转换它。但就您而言,这还不够。在标准库中,所有移动构造函数都具有 Type(Type&&)
的签名,而不是 Type(const Type&&)
。如果你传递一个 const 值,即使你用 std::move
转换它,它也会调用复制构造函数,而不是移动构造函数。为了调用移动构造函数,您的对象不能是常量。
所以你移动向量的构造函数*应该是这样的:
Mystruct(std::vector<int>&& w): v(std::move(w))
{
std::cout << "Move Constructor :" << v.at(0) << "\n";
}
并且为了比较地址以查看它是否真的被移动,您不应该比较 v
和 w
的地址(它们不会,也不能改变),但是 v.data()
和w.data()
,指向vector动态分配的资源。
*不是移动构造函数。移动构造函数的签名为 Mystruct(Mystruct&&)
或 Mystruct(const Mystruct&&)
我有一个 class,里面有一个 std::vector
像
struct Mystruct
{
Mystruct(const std::vector<int>& w): v(w)
{
std::cout << "Copy constructor :" << v.at(0) << "\n";
}
Mystruct(const std::vector<int>&& w): v(w)
{
std::cout << "Move Constructor :" << v.at(0) << "\n";
}
private:
std::vector<int> v;
};
然后我创建了像
这样的对象int main()
{
auto x = std::vector<int> {1,2,3};
Mystruct M1(x);
Mystruct M2(std::vector<int> {3,2,1});
return 0;
}
M1
是使用复制构造函数构造的,M2
是使用"move"构造函数构造的,但是在gdb中运行两个赋值都为v和w保留了不同的地址,如果我在第二个构造函数的初始化列表中使用 v (std::move(w)),也会发生同样的情况。所以我猜这两个赋值都在复制 w 的内容,这是正确的吗?如果是这样,我怎样才能移动 w 的内容而不是复制它们
首先,移动对象不会改变它的地址。根据定义,您不能更改对象的地址,因为地址是对象定义的一部分。如果你有一个不同的地址,你有一个不同的对象。移动的作用(至少就标准库中的 类 而言)是转移对象动态分配资源的所有权。
其次,你没有移动任何东西。为了移动某些东西,你必须调用移动构造函数。这意味着您需要传递一个 r 值。命名对象永远不是右值。所以即使你有一个 r 值引用,你仍然需要用 std::move
来转换它。但就您而言,这还不够。在标准库中,所有移动构造函数都具有 Type(Type&&)
的签名,而不是 Type(const Type&&)
。如果你传递一个 const 值,即使你用 std::move
转换它,它也会调用复制构造函数,而不是移动构造函数。为了调用移动构造函数,您的对象不能是常量。
所以你移动向量的构造函数*应该是这样的:
Mystruct(std::vector<int>&& w): v(std::move(w))
{
std::cout << "Move Constructor :" << v.at(0) << "\n";
}
并且为了比较地址以查看它是否真的被移动,您不应该比较 v
和 w
的地址(它们不会,也不能改变),但是 v.data()
和w.data()
,指向vector动态分配的资源。
*不是移动构造函数。移动构造函数的签名为 Mystruct(Mystruct&&)
或 Mystruct(const Mystruct&&)