[英]rvalue reference and move of a local variable
在這個片段中,我分配了一個本地 object B,我將它傳遞給另一個 object C 的構造函數,它將它作為右值引用。 然后我將后者放入容器中。
當我檢索 C 並將其成員 static_cast 回 B 時,該值不正確(並且 valgrind 識別出 18 個錯誤!)
#include <iostream>
#include <memory>
#include <vector>
class A {
public:
virtual ~A() {};
};
class B: public A {
public:
B(int foo) : _foo(foo) {}
int _foo;
};
class C {
public:
C(A&& a): _a(std::move(a)) {}
A&& _a;
};
std::vector<C> v;
void bar() {
v.emplace_back(B(12));
}
int main() {
bar();
C&& c = std::move(v.front());
std::cout << static_cast<B&&>(c._a)._foo << std::endl;
return 0;
}
我的理解是,由於 C 采用右值引用,因此不應有任何 object 切片。 我應該仍然能夠檢索到完整的 B object。 此外,我對std::move
的理解(很可能是有缺陷的)是我可以將局部變量“移動”出其上下文,並且通過獲取右值引用,C 獲得 B 的所有權。
output 是39931504
而不是12
。
任何人都可以向我解釋發生了什么?
我應該仍然能夠檢索到完整的 B object。
如果它不是在控制到達bar
的右括號時不存在的臨時變量,那么您會是。 您在C
中持有參考,而對臨時 object 的參考很快就會變得懸空。
一個快速的解決方法是簡單地將C
的成員聲明更改為std::unique_ptr<A> a;
並正確地初始化它,比如說,
template<class AChild> C(AChild child)
: a(std::make_unique<AChild>(std::move(child))) {};
(按口味添加 SFINAE)。
問題是 class C
中對A
的引用(即數據成員_a
)比它所指的 object 的壽命更長。 這是因為bar()
中的臨時B(12)
) function
void bar() {
v.emplace_back(B(12));
}
從bar()
返回后不存在。 因此, class C
包含的對A
的引用成為懸空引用。
您可以使用new
運算符創建B
object 而不是臨時的:
void bar() {
B* ptr = new B(12);
v.emplace_back(std::move(*ptr));
}
從bar()
返回時,此B
object 不會停止存在,因此C
中對A
的引用仍然有效。
請注意,使用這種方法,您需要手動銷毀 object:
C&& c = std::move(v.front());
// ...
delete &c._a; // destroy object
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.