我可以在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错误?或者它的工作原理应该如何?
答案 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;