簡體   English   中英

基於范圍的for循環中的臨時對象

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM