移动构造函数未按预期方式被调用 [英] move constructor not being called as expected

查看:124
本文介绍了移动构造函数未按预期方式被调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是C ++ 0x的新手,我想把我的头放在右值引用周围,并移动构造函数。我正在使用带有-std = c ++ 0x的g ++ 4.4.6,并且对以下代码感到困惑:

I'm new to C++0x and I'm trying to wrap my head around rvalue references and move constructors. I'm using g++ 4.4.6 with -std=c++0x, and I'm confused by the following piece of code:



    class Foo 
    {
    public:
      Foo() 
        : p( new int(0) )
      {
        printf("default ctor\n");
      }

      Foo( int i )
        : p( new int(i) )
      {
        printf("int ctor\n");
      }

      ~Foo() 
      {
        delete p;
        printf("destructor\n");
      }

      Foo( const Foo& other ) 
        : p( new int( other.value() ) )
      {
        printf("copy ctor\n");
      }


      Foo( Foo&& other )
        : p( other.p )
      {
        printf("move ctor\n");
        other.p = NULL;
      }

      int value() const 
      {
        return *p;
      }

    private:
      // make sure these don't get called by mistake
      Foo& operator=( const Foo& );
      Foo& operator=( Foo&& );

      int* p;
    };


    Foo make_foo(int i) 
    {
      // create two local objects and conditionally return one or the other
      // to prevent RVO
      Foo tmp1(i);
      Foo tmp2(i);

      // With std::move, it does indeed use the move constructor
      //  return i ? std::move(tmp1) : std::move(tmp2);
      return i ? tmp1 : tmp2;

    }


    int main(void) 
    {
      Foo f = make_foo( 3 );

      printf("f.i is %d\n", f.value());

      return 0;
    }

我发现在编写时,编译器使用了复制构造函数在main()中构建对象。当我在make_foo()中使用std :: move行时,则在main()中使用move构造函数。为什么在make_foo()中需要std :: move?我会认为,尽管tmp1和tmp2在make_foo()中被命名为对象,但是当它们从函数返回时,它们应该成为临时对象。

I find that as written, the compiler uses the copy constructor build the object in main(). When I use the std::move line inside make_foo(), then the move constructor is used in main(). Why is std::move necessary inside make_foo()? I would think that although tmp1 and tmp2 are named objects inside make_foo(), when they're returned from a function they should become temporaries.

推荐答案

这是您的问题:

return i ? tmp1 : tmp2;

仅在return语句为正的情况下,函数中的局部变量才会从return语句中移出 return var; 。如果要进行测试,则需要使用if:

A local variable in a function will only be moved from in the return statement if the return statement is just return var;. If you want to do that test you will need to use an if:

if (i) {
   return tmp1;
} else {
   return tmp2;
}

引文有点令人费解,但它分别位于12.8 / 31和12.8 / 32

The citation is a bit convoluted, but it is in 12.8/31 and 12.8/32


12.8 / 32当满足或将要满足复制操作的省略标准时,源对象除外是一个函数参数,并且要复制的对象由左值指定,首先执行重载决议以选择要复制的构造函数,就好像该对象由右值指定了[...]

12.8/32 When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue [...]

即使表达式是一个左值,当满足12.8 / 31中的条件时,它将被视为右值,即该块中的第二个选项是:

That is even if the expression is an lvalue, it will be considered to be an rvalue when the criteria in 12.8/31 is met, the second option in that block is:


12.8 / 31在具有类返回类型的函数中的return语句中,当表达式是非具有与函数返回类型相同的cv不合格类型的易失性自动对象(函数或捕获子句参数除外),可以省略复制/移动操作通过将自动对象直接构造为函数的返回值。

12.8/31 in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value.

哪个确定返回tmp; 允许复制省略,但返回(cond?tmp:tmp); 不允许。

Which determines that return tmp; allows for copy elision, but return (cond?tmp:tmp); doesn't.

请注意,为了使编译器在return语句中生成隐式 std :: move ,返回的对象必须是省略的候选对象,除非它也是功能。使用条件运算会禁止复制省略,同时会禁止编译器移出对象。第二种情况可能更容易编写代码:

Note that for the compiler to generate an implicit std::move in the return statement, the returned object must be a candidate for elision unless the it is also an argument to the function. Using the conditional operation inhibits copy elision, and at the same time inhibits the compiler from doing moving out of your objects. That second case might be simpler to code:

Foo make_foo(Foo src) {
   return src;           // Copy cannot be elided as 'src' is an argument
}

这篇关于移动构造函数未按预期方式被调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆