簡體   English   中英

在std :: bitset :: operator []中創建的std :: bitset :: reference對象的生命周期?

[英]Lifetime of std::bitset::reference object created in std::bitset::operator[]?

我一直在看bitset標准C ++庫頭文件的頭文件。 我發現重載的operator [] operator[](size_t ndx) (在類bitset定義)返回類reference的temproray對象。

reference
    operator[](size_t __position)
{ return reference(*this,__position); }

這個重載的運算符封裝了單個位的概念。 此類的實例是實際位的代理。 它在像這樣的表達式中很有用

bitset<10> b;
b[2] = true;

reference類定義了overloaded = operator成員函數,以便上面的示例可以工作:

 //For b[i] = __x;
 reference&
     operator=(bool __x)
 {
   if (__x)
     *_M_wp |= _Base::_S_maskbit(_M_bpos);
   else
     *_M_wp &= ~_Base::_S_maskbit(_M_bpos);
   return *this;
}

但是,我對這個表達感到困惑:

if (b[2]) {
    //Do something
}

b[2]首先返回類reference的臨時對象,然后在返回的臨時對象上調用重載的operator( operator bool() const ),將其轉換為bool數據類型。

// For __x = b[i];
operator bool() const
{ return (*(_M_wp) & _Base::_S_maskbit(_M_bpos)) != 0; }

如果臨時對象(具有自動存儲類對象)的上棧創建的,則調用一個另一個函數( operator bool() const )不應該破壞由所述第一函數調用返回的臨時對象( reference由返回的對象reference operator[](size_t __position) )?

C和C ++中臨時對象的生命周期是多少?

來自class.temporary#4 ,強調是我的。

當實現引入具有非平凡構造函數([class.ctor],[class.copy])的類的臨時對象時,它應確保為臨時對象調用構造函數。 類似地,析構函數應該用一個非平凡的析構函數([class.dtor])來調用。 臨時對象作為評估全表達式([intro.execution])的最后一步被銷毀,該表達式(詞法上)包含創建它們的點。 即使該評估以拋出異常結束,也是如此。 銷毀臨時對象的值計算和副作用僅與完整表達相關聯,而不與任何特定子表達相關聯。

該臨時對象將在該給定表達式的最后一步被銷毀。

實際上,C ++依賴於它,因為這個非常常見的表達式可以正常工作:

int x = 0, y = 0, z = 0, t = 0;
int a = x + y + z + t;

因為x+y是臨時的, x+y+z是另一個臨時的。


根據class.temporary#5中的規則,臨時的生命周期將縮短

有三種情況下,臨時表在與完整表達結束時不同的地方被摧毀。 第一個上下文是調用默認構造函數來初始化沒有相應初始值設定項的數組元素([dcl.init])。 第二個上下文是在復制整個數組時調用復制構造函數來復制數組元素([expr.prim.lambda],[class.copy])。 在任何一種情況下,如果構造函數具有一個或多個默認參數,則在構造下一個數組元素(如果有)之前,對默認參數中創建的每個臨時的銷毀進行排序。

並且會在課堂上遵循規則延長。 當前#6

第三個上下文是引用綁定到臨時的時間.11引用綁定的臨時值或引用綁定到的子對象的完整對象的臨時值在引用的生存期內持續存在,除了:

  • 綁定到函數調用([expr.call])中的引用參數的臨時對象將持續存在,直到包含該調用的完整表達式完成。

  • 函數返回語句([stmt.return])中返回值臨時綁定的生命周期未擴展; 臨時在return語句中的full-expression結束時被銷毀。

  • 在new-initializer([expr.new])中對引用的臨時綁定將持續到包含new-initializer的full-expression完成為止。

在這個例子中可以看到第一個上下文:

struct bar {
    bar() { std::cout << __func__ << '\n'; }
    bar(const bar&) { std::cout << __func__ << "__\n"; }
    ~bar() { std::cout << __func__ << '\n'; }
};

struct foo {
    foo(const bar& b = bar()) { std::cout << __func__ << '\n'; }
};

int main() {
    foo f[] = {foo(), foo()};
}

以上程序應輸出:

bar
foo
~bar
bar
foo
~bar

第二個上下文將添加到C ++ 17,從那時起該程序:

struct bar {
    bar() { std::cout << __func__ << '\n'; }
    bar(const bar&) { std::cout << __func__ << "__\n"; }
    ~bar() { std::cout << __func__ << '\n'; }
};

struct foo {
    foo() {}
    foo(const foo&, const bar& b = bar()) { std::cout << __func__ << "__\n"; }
};

struct foox {
    foo f[2];
};

int main() {
    foox fx;
    foox yx = fx;
}

必須輸出:

bar
foo__
~bar
bar
foo__
~bar

對於第三種情況下,你可以找到答案在這里 ,並在這里

包含operator bool() if (b[2])的條件是單個表達式,臨時值對表達式的整個生命周期有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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