关于我在测试将参数作为左值复制、右值移动和通过引用传递时观察到的行为的问题

Question on behavior I have observing when testing passing parameter as lvalue-copy, rvalue-move and pass by ref

本文关键字:引用 问题 观察 测试 于我 参数 复制 移动      更新时间:2024-05-23

在下面的代码中,我正在测试堆栈中的按左值传递(应通过复制构造函数(、右值(应通过移动构造函数(和按引用传递(不应调用构造函数(。然而,当执行Func(MyType1(((行时,我认为MyType1是一个r值,应该触发move构造函数。是,在输出中,它显示它既不触发复制构造函数,也不触发移动构造函数。它似乎通过传递或传递左值或右值引用。为什么?

第二个问题可能是由于我的误解,可以采取行动。在我的类中,MyType1对象有一个char数组。在复制/移动两者中,似乎对于数组,我只能做深度复制;而不是通过调整指针来进行浅层复制(我的目标是避免昂贵的逐元素数组深层复制(。理想情况下,在move c'tor中,我认为我可以使新对象的数据指向堆栈中的现有数组,而使源堆栈对象中的数组指针为null。但这似乎只适用于堆对象指针。我是不是错过了什么?

在dc 0x7fff33727e114 中

在cc 0x7fff33727e11e 中

在Func 中

在0x7fff33727e11e 中

在mc 0x7fff33727e11e 中

在Func 中

在0x7fff33727e11e 中

在dc 0x7fff33727e11e中

在Func

a a a a a a a a

在de 0x7fff33727e11e中

在FuncRef 中

a a a a

在0x7fff33727e114 中

class MyType1
{
public:
~MyType1() 
{
cout << "in de " << this << "n";
}
MyType1()
{
cout << "in dc " << this << "n";
for (int i = 0; i < 10; i++)
{
data[i] = 'a';
}
}
MyType1(MyType1 &o)
{
cout << "in cc " << this << "n ";
// *data = *o.data; doesn't work, have to deep copy?
}
MyType1(MyType1 &&o)
{
cout << "in mc "<< this << "n ";
// *data = *o.data; doesn't work, have to deep copy? also can't free source array?
}
void Print()
{
for (int i = 0; i < 10; i++)
{
cout << data[i] << " ";
}
cout << "n";
}
char data[10];
};
void Func(MyType1 other)
{
cout << "in Funcn";
other.Print();
}
void FuncRef(MyType1& other)
{
cout << "in FuncRefn";
other.Print();
}

int main()
{
MyType1 t;
Func(t);
Func(std::move(t));
Func(MyType1());
FuncRef(t);
}

这并不能完全回答你的问题,但(我认为(切中了你误解的核心。

考虑以下结构:

struct One {
char data[10];
};

那个结构体有10个字节长。类型为One的每个对象都包含一个由十个元素组成的数组。不是指向数组的指针,而是实际的数组。

所以当你说你想做一个";浅拷贝";,这是什么意思?你不能"指向数组";在另一个数组中,数组不是这样工作的。如果您有一个指针,您可以这样做,但结构体One不存储指针,只存储一个数组。(是的,您可以制作一个指向data的指针,但不能将该指针存储在One类型的对象中(

将数组作为One对象的一部分也意味着数组的存储只与它所属的对象一样长。所以即使你可以";重新指向";阵列,当原始(源(对象被销毁(并且存储被重用(时,这将导致问题。

您在这里问了两个问题:

  1. 为什么Func(MyType1());没有在默认ctor之后调用move ctor?答案是";复制省略":C++标准允许跳过复制或移动构造函数,而使用原始对象(从C++17开始,在某些情况下省略是强制性的(。规则在不同版本的标准之间变化,并且很复杂。您永远不应该依赖于正在调用的复制/移动构造函数
  2. 您理解得对:如果不使用堆,就无法使用move构造函数进行优化