我有一个同时实现move和copy构造函数的ArrayWrapper类。
我有2个问题。
您可以看到在我的代码中,复制构造函数ArrayWrapper (ArrayWrapper& other)
与移动构造函数ArrayWrapper (ArrayWrapper&& other)
完全相同!两者的工作原理相同,并且经过的时间相同。 (我注释掉了原始的复制构造函数)复制和移动构造函数如何使用相同的代码并且仍然有效?
代码实际上并没有触及move构造函数(我怀疑这是我第一个问题起作用的原因),我在两个函数中均添加了注释,并且输出未显示出正在调用move构造函数,即使我传递了右值引用ArrayWrapper d3(ArrayWrapper(10000000));
。我在做什么错了?
#include <bits/stdc++.h>
#include <chrono>
using namespace std;
using namespace std::chrono;
class ArrayWrapper
{
public:
ArrayWrapper ()
: _p_vals( new int[ 64 ] )
, _size( 64 )
{
cout<<"?"<<endl;
}
ArrayWrapper (int n)
: _p_vals( new int[ n ] )
, _size( n )
{
}
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _size( other._size )
{
cout<<"Move"<<endl;
other._p_vals = NULL;
other._size = 0;
}
ArrayWrapper (ArrayWrapper& other)
: _p_vals( other._p_vals )
, _size( other._size )
{
cout<<"Copy constructor"<<endl;
other._p_vals = NULL;
other._size = 0;
}
/*
// copy constructor
ArrayWrapper (const ArrayWrapper& other)
: _p_vals( new int[ other._size ] )
, _size( other._size )
{
for ( int i = 0; i < _size; ++i )
{
_p_vals[ i ] = other._p_vals[ i ];
}
}
*/
void generate(){
for(int i=0; i<_size; i++){
_p_vals[i] = i;
}
}
~ArrayWrapper ()
{
delete [] _p_vals;
}
void print(){
for(int i=0; i<_size;i++){
cout<<_p_vals[i]<<" ";
}
cout<<endl;
}
private:
int *_p_vals;
int _size;
};
int main(){
auto start = high_resolution_clock::now();
ArrayWrapper d(10000000);
ArrayWrapper d2(d); //deep copy
auto stop= high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
cout << duration.count() << endl;
auto start2 = high_resolution_clock::now();
ArrayWrapper d3(ArrayWrapper(10000000)); //shallow copy
auto stop2 = high_resolution_clock::now();
auto duration2 = duration_cast<microseconds>(stop2 - start2);
cout << duration2.count() << endl;
}
答案 0 :(得分:3)
两者的工作原理相同...复制和移动构造函数如何使用相同的代码并且仍然有效?
该函数的主体执行相同的操作,因此其工作方式相同。
关于复制构造函数“有效”的含义:复制构造函数修改操作数是非常不习惯的。许多人会同意它以错误的方式“起作用”。
P.S。在标准库中std::auto_ptr
曾经有一个智能指针,该指针获取了传递给副本构造函数的指针的所有权。试图在移动语义存在之前实现唯一指针。由于我们确实拥有move构造函数,因此不再需要这样做。 std::auto_ptr
有充分的理由被从标准中删除。
代码实际上并没有击中move构造函数...我在做什么错了?
您正在从相同类型的prvalue表达式初始化。 d3
是使用ArrayWrapper(10000000)
的初始化程序表达式直接构造的,没有任何临时对象。换句话说,仅使用ArrayWrapper (int n)
;不是move构造函数。
在C ++ 17之前,存在一个临时对象,该对象将从涉及抽象机的地方移开,但是即使那样,该移动也可以被忽略,这与上面的意思相同(没有临时的,没有采取任何措施),只是它只是一种允许的优化,并非标准强制要求的优化。
您做错了什么,就是期望有一个动作,或者该动作肯定会产生副作用。
答案 1 :(得分:2)
您可以看到在我的代码中,复制构造函数
ArrayWrapper (ArrayWrapper& other)
与移动构造函数ArrayWrapper (ArrayWrapper&& other)
完全相同!两者的工作原理相同,并且经过的时间相同。 (我注释掉了原始的复制构造函数)复制和移动构造函数如何使用相同的代码并且仍然有效?
复制构造函数和move构造函数唯一可以完全相同的时间是在处理只能复制的类型(或移动它们是为了获得副本)时。这不是你所拥有的。在
ArrayWrapper (ArrayWrapper& other)
: _p_vals( other._p_vals )
, _size( other._size )
{
cout<<"Copy constructor"<<endl;
other._p_vals = NULL;
other._size = 0;
}
您基本上有一个左值移动构造函数。如果要在d
之后打印ArrayWrapper d2(d);
的大小,则会得到0
,因为您窃取了它的数据。这并不是要复制,并且确实会使很多程序员感到困惑,因为它所做的事情完全出乎意料。如果您确实要制作副本,则需要使用ArrayWrapper (const ArrayWrapper& other)
中的代码。