移动构造函数的用处

时间:2013-07-11 06:58:03

标签: c++ c++11 move-semantics

我在http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html

上找到了这个例子
   #include <iostream>
    using namespace std;

class ArrayWrapper
    {
    public:
        // default constructor produces a moderately sized array
        ArrayWrapper ()
            : _p_vals( new int[ 64 ] )
            , _size( 64 )
        {}

        ArrayWrapper (int n)
            : _p_vals( new int[ n ] )
            , _size( n )
        {}

        // move constructor
        ArrayWrapper (ArrayWrapper&& other)
            : _p_vals( other._p_vals  )
            , _size( other._size )
        {
            cout<<"move constructor"<<endl;
            other._p_vals = NULL;
        }

        // copy constructor
        ArrayWrapper (const ArrayWrapper& other)
            : _p_vals( new int[ other._size  ] )
            , _size( other._size )
        {
            cout<<"copy constructor"<<endl;
            for ( int i = 0; i < _size; ++i )
            {
                _p_vals[ i ] = other._p_vals[ i ];
            }
        }
        ~ArrayWrapper ()
        {
            delete [] _p_vals;
        }

    private:
        int *_p_vals;
        int _size;
    };

    int main()
    {   
            ArrayWrapper a(20);
            ArrayWrapper b(a);

    }

有人可以给我一些例子(最有用的情况),其中该类中的移动构造函数采取行动吗? 我理解了这种构造函数的目的,但我无法确定它何时会在实际应用程序中使用。

2 个答案:

答案 0 :(得分:0)

此示例中未使用移动构造函数,因为a是左值。但是,如果你有一个返回ArrayWrapper的函数,即ArrayWrapper func(),那么它的函数调用结果将是一个右值,因此当你执行ArrayWrapper b(func())时会使用移动构造函数。

这可能是一个好的开始:http://thbecker.net/articles/rvalue_references/section_01.html

答案 1 :(得分:0)

void do_something_complex( ArrayWrapper data );

int main()
{
   do_something_complex( ArrayWrapper( 42 ) );
}

这里对函数的调用将创建一个临时的ArrayWrapper,其中的数据将被移动到函数内而不是复制,这意味着只需设置一个指针而不必将所有数据从临时复制到函数内部参数

这是一个更常见的变体:

ArrayWrapper generate_random_data( int seed );

void do_something_complex( ArrayWrapper data );

int main()
{
   do_something_complex( generate_random_data( 42 ) );
}    

同样的事情发生了:生成函数返回的数据被移动(使用移动构造函数),而不是复制,在do something函数参数中。

进一步澄清:

ArrayWrapper generate_random_data( int seed )
{
    int random_count = random( 0, 42, seed ); // lets say this work
    return ArrayWrapper( seed );
}

这可能发生两件事。首先,移动构造函数将用于将返回的对象传递给函数外部,不需要使用指针或类似的东西(如果没有移动构造函数,则将使用复制构造函数)。其次,如果你有:

ArrayWrapper a = generate_random_data( 42 );

然后大多数编译器将生成一个名为NRVO的授权优化,其基本上是返回的对象将在外部分配的对象内部构建,这里是'a'。

这意味着如果可以,编译器将避免移动和复制构造。如果它无法避免两者,当确定物体不会比移动更远时,它将尝试移动物体。如果无法确定,那么它将使用副本。