[英]A temporary object in range-based for-loop
在Range-based for loop on a temporary range中, Barry提到以下內容不受被破壞的臨時對象的影響,並且我測試了成員v
確實存在於整個for
循環中(因為析構函數~X
在整個for
循環)。 解釋是什么?
struct X {
std::vector<int> v;
~X()
{
}
};
X foo()
{
return X();
}
for (auto e : foo().v) {
// ok!
}
這是一種晦澀的臨時延長壽命形式。 通常,您必須將臨時對象直接綁定到引用以使其工作(例如for (auto x : foo())
),但根據 cppreference,此效果通過以下方式傳播:
( )
(分組,不是函數調用),[ ]
(未重載;必須使用數組而不是指針),.
, .*
,? :
? :
,,
(未重載), 即,如果ab
綁定到一個引用,則a
的生命周期會延長。
當引用變量直接綁定到臨時變量時,可以實現臨時生命周期延長,但不僅如此。 有關臨時生命周期延長的確切列表,請參閱規范: [class.temporary] 。
尊者@HolyBlackCat提供的答案非常好,但我覺得需要一些例子。
⦿ 直接綁定臨時
// function prototype
std::string foo();
// calling foo:
const auto& b = foo(); // lifetime is extended, directly bind to a temporary
// also, similarly:
const std::string& s = "hi"; // lifetime is extended, the same
根據語言規則,在以下任何一種情況下,也可以實現臨時延長壽命:
⦿ 括號 ( ) (分組,不是函數調用)
const auto& a = (foo()); // lifetime is extended, grouping with parenths is ok
const std::string& s = ("hello "s + "world"); // lifetime is extended, the same
對於接下來的情況,讓我們添加以下結構:
struct A {
std::string str = "hey";
int arr[3] = {2, 3, 4};
int* ptr = arr;
const auto& foo() const {
return str;
}
};
⦿ 會員訪問 ., .*
const auto& b1 = A().str; // lifetime of A() is extended
const auto& b2 = A().arr; // lifetime of A() is extended
const auto& b3 = A().ptr; // lifetime of A() is extended
// BUT -
const auto& b4 = *A().ptr; // lifetime of A() is NOT extended (b4 dangling)
// pointer to member access
const auto& str_ptr = &A::str;
const auto& arr_ptr = &A::arr;
const auto& ptr_ptr = &A::ptr;
const auto& c1 = A().*str_ptr; // lifetime of A() is extended
const auto& c2 = A().*arr_ptr; // lifetime of A() is extended
const auto& c3 = A().*ptr_ptr; // lifetime of A() is extended
// BUT - not for a member function
const auto& foo_ptr = &A::foo;
// below initialization is bounded to a function call result
// not to a member access
const auto& c4 = (A().*foo_ptr)(); // lifetime of A() is NOT extended (c4 dangling)
⦿ 數組訪問 [ ] (不重載;必須使用數組而不是指針)
const auto& d1 = A().arr[0]; // lifetime of A() is extended
// BUT - not for pointers
// pointer access with []
const auto& d2 = A().ptr[0]; // lifetime of A() is NOT extended (d2 dangling)
// neither for overloaded []
const auto& d3 = A().str[0]; // lifetime of A() is NOT extended (d3 dangling)
⦿ 三元運算符? :
const auto& e1 = true? A() : A(); // lifetime of the 1st A() is extended
const auto& e2 = false? A() : A(); // lifetime of the 2nd A() is extended
⦿ 逗號運算符 ,(未重載)
const auto& f1 = (A(), A()); // lifetime of the 2nd A() is extended
⦿ 任何不涉及“用戶定義的轉換”的轉換(可能不使用構造函數或轉換運算符)
const auto& g1 = const_cast<const A&&>(A()); // lifetime of A() is extended
const double& g2 = A().arr[0]; // lifetime of A() is NOT extended
// but this is a valid ref to a double
// converted from an int, as a temporary
對於不延長生命周期的強制轉換,讓我們添加一個額外的類:
class B {
const A& a;
public:
B(const A& a): a(a){}
};
以下轉換經過用戶定義的轉換,因此不會延長 A 的生命周期:
const auto& g3 = ((B&&)A()); // lifetime of A() is NOT extended (g3 dangling)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.