【问题标题】:Usefulness of move constructor [duplicate]移动构造函数的用处[重复]
【发布时间】:2013-07-11 06:58:03
【问题描述】:

我在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);

    }

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

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:
      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 ) );
      }    
      

      同样的事情发生了:generate 函数返回的数据被移动(使用移动构造函数),而不是复制,在 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'。

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

      【讨论】:

      • 显然它没有调用移动构造函数。只有第二个构造函数。
      • @iulian 你在说哪一部分?我所说的 NRVO 优化确实避免了移动。如果您看到 int 构造函数调用但没有其他构造函数,则它避免了移动和复制。
      • 好的,现在我明白了。我还没有阅读 NRVO 问题。谢谢。
      猜你喜欢
      • 1970-01-01
      • 2016-06-20
      • 1970-01-01
      • 2011-05-22
      • 2023-03-11
      • 1970-01-01
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多