C ++ 11右值对象字段

时间:2014-05-17 11:42:26

标签: c++11 rvalue-reference rvalue

我可以在c ++ 11中使用rvalue字段的类/结构吗? 像这样:

template<typename T>
struct RvalueTest{
    RvalueTest(T&& value) : value( std::forward<T>(value) ){}
    T&& value;
};

因为在以下测试中:

class Widget {
public:
  Widget(){std::cout << "Widget ctor  " << std::endl; }
  Widget(int h) : h(h){std::cout << "Widget ctor param " << std::endl; }

  Widget(const Widget&) { std::cout << "Widget copy ctor  " << std::endl;  }
  Widget(Widget&&) { std::cout << "Widget move ctor  " << std::endl;  }           // added this

  template<typename T>
  Widget(const T&) { std::cout << "Generalized Widget copy ctor  " << std::endl;  }

  template<typename T>
  Widget(T&&) { std::cout << "Universal Widget ctor  " << std::endl;  }

  int h;
};

RvalueTest<Widget> r(Widget(12));
std::cout << r.value.h;

我输出时有一些垃圾值(含-O2):
http://coliru.stacked-crooked.com/a/7d7bada1dacf5352

Widget ctor param
4203470

正确的值与-O0:
http://coliru.stacked-crooked.com/a/f29a8469ec179046

Widget ctor param
12

WHY ???

P.S。我尝试实现的是单个ctor调用,没有任何额外的移动/复制构造函数。


已更新

它与clang编译好 http://coliru.stacked-crooked.com/a/6a92105f5f85b943
GCC错误?或者它的工作原理应该如何?

1 个答案:

答案 0 :(得分:0)

问题并非特定于右值引用。如果您用 const T&amp; 替换 T&amp;&amp; ,您将会看到相同的奇怪行为。

template<typename T>
struct ReferenceTest{
    ReferenceTest(const T& value) : value(value){}
    const T& value;
};

问题是,您正在存储对临时对象的引用。临时对象在创建语句的末尾会自动销毁,但您稍后会尝试通过引用访问它。

RvalueTest<Widget> r(Widget(12)); // pass reference to temporary object to constructor
std::cout << r.value.h; // invalid reference

可以使用 rvalue references 作为成员变量。但是,如果这样做,你必须要小心。标准库中的一个示例是std::forward_as_tuple

auto t = std::forward_as_tuple(42);
// t has type std::tuple<int&&>

关于如何避免复制或移动构造的问题:不要使用 rvalue reference 成员变量。以下是两种方法,您可以使用:

std :: unique_ptr:如果复制或移动小部件太贵,可以使用智能指针:

template <typename T>
struct Test
{
    std::unique_ptr<T> _value;
    explicit Test(std::unique_ptr<T> value) : _value{std::move(value)} { }
};

Test<Widget> t{std::make_unique<Widget>(12)};
std::cout << t._value->h;

第二种方法就地创建 Widget 。这就是标准容器的不同 emplace 功能的作用,例如: std::vector::emplace_back

template <typename T>
struct Test
{
    T _value;
    template <typename ...Args>
    explicit Test(Args&&... args) : _value{std::forward<Args>(args)...} { }
};

Test<Widget> t{12};
std::cout << t._value.h;