创建一个对象,局部变量与右值引用
Creating an object, local variable vs rvalue reference
创建对象时使用 r 值引用是否有任何优势,否则该对象将位于普通局部变量中?
Foo&& cn = Foo();
cn.m_flag = 1;
bar.m_foo = std::move(cn);
//cn is not used again
Foo cn;
cn.m_flag = 1;
bar.m_foo = std::move(cn); //Is it ok to move a non rvalue reference?
//cn is not used again
在第一个代码片段中,显然不会有任何副本,但我猜想在第二个代码片段中编译会优化副本吗?
同样在第一个片段中,对象实际存储在内存中的什么位置(在第二个片段中,它存储在封闭函数的堆栈帧中)?
这些代码片段大部分是等价的。这个:
Foo&& rf = Foo();
正在将临时对象绑定到引用,从而将临时对象的生命周期延长到引用的生命周期。 Foo
只会在 rf
超出范围时被销毁。这与您得到的行为相同:
Foo f;
除了在后一个示例中 f
是默认初始化的,而在前一个示例中 rf
是值初始化的。对于某些类型,两者是等效的。对于其他人,他们不是。如果您改为写 Foo f{}
,那么这种差异就会消失。
剩下的一个区别与复制省略有关:
Foo give_a_foo_rv() {
Foo&& rf = Foo();
return rf;
}
Foo give_a_foo() {
Foo f{};
return f;
}
第一个例子不允许执行RVO,因为rf
与give_a_foo_rv()
的return类型不相同。此外,rf
甚至不会自动移动到 return 类型,因为它不是一个对象,所以它没有自动存储持续时间,所以这是一个额外的副本(直到 C++20,在这是一个额外的举动):
Foo f = give_a_foo_rv(); // a copy happens here!
Foo g = give_a_foo(); // no move or copy
it seems clear that there will not be any copies
这完全取决于移动 Foo
的实际作用。如果 Foo
看起来像:
struct Foo {
Foo() = default;
Foo(Foo const& ) = default;
Foo& operator=(Foo const& ) = default;
// some members
};
然后移动 Foo
仍然进行复制。
是的,在第二个例子中 std::move(f)
完全没问题。您不需要从 T
到 move
的类型右值引用的对象。这将严重限制移动的实用性。
创建对象时使用 r 值引用是否有任何优势,否则该对象将位于普通局部变量中?
Foo&& cn = Foo();
cn.m_flag = 1;
bar.m_foo = std::move(cn);
//cn is not used again
Foo cn;
cn.m_flag = 1;
bar.m_foo = std::move(cn); //Is it ok to move a non rvalue reference?
//cn is not used again
在第一个代码片段中,显然不会有任何副本,但我猜想在第二个代码片段中编译会优化副本吗?
同样在第一个片段中,对象实际存储在内存中的什么位置(在第二个片段中,它存储在封闭函数的堆栈帧中)?
这些代码片段大部分是等价的。这个:
Foo&& rf = Foo();
正在将临时对象绑定到引用,从而将临时对象的生命周期延长到引用的生命周期。 Foo
只会在 rf
超出范围时被销毁。这与您得到的行为相同:
Foo f;
除了在后一个示例中 f
是默认初始化的,而在前一个示例中 rf
是值初始化的。对于某些类型,两者是等效的。对于其他人,他们不是。如果您改为写 Foo f{}
,那么这种差异就会消失。
剩下的一个区别与复制省略有关:
Foo give_a_foo_rv() {
Foo&& rf = Foo();
return rf;
}
Foo give_a_foo() {
Foo f{};
return f;
}
第一个例子不允许执行RVO,因为rf
与give_a_foo_rv()
的return类型不相同。此外,rf
甚至不会自动移动到 return 类型,因为它不是一个对象,所以它没有自动存储持续时间,所以这是一个额外的副本(直到 C++20,在这是一个额外的举动):
Foo f = give_a_foo_rv(); // a copy happens here!
Foo g = give_a_foo(); // no move or copy
it seems clear that there will not be any copies
这完全取决于移动 Foo
的实际作用。如果 Foo
看起来像:
struct Foo {
Foo() = default;
Foo(Foo const& ) = default;
Foo& operator=(Foo const& ) = default;
// some members
};
然后移动 Foo
仍然进行复制。
是的,在第二个例子中 std::move(f)
完全没问题。您不需要从 T
到 move
的类型右值引用的对象。这将严重限制移动的实用性。