复制构造函数和move构造函数具有相同的运行时间,并且未调用move构造函数

时间:2019-05-10 16:36:26

标签: c++

我有一个同时实现move和copy构造函数的ArrayWrapper类。

我有2个问题。

  1. 您可以看到在我的代码中,复制构造函数ArrayWrapper (ArrayWrapper& other)与移动构造函数ArrayWrapper (ArrayWrapper&& other)完全相同!两者的工作原理相同,并且经过的时间相同。 (我注释掉了原始的复制构造函数)复制和移动构造函数如何使用相同的代码并且仍然有效?

  2. 代码实际上并没有触及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;
    
    }
    

2 个答案:

答案 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)中的代码。