簡體   English   中英

兩個臨時對象的地址在同一個表達式中是否保證不同?

[英]Are the addresses of two temporaries guaranteed to be different in the same expression?

考慮以下程序:

#include <iostream>

int const * f(int const &i) 
{ 
  return &i; 
}

int main() 
{
  std::cout << f(42);  // #1
  std::cout << f(42);  // #2

  std::cout << f(42) << f(42);  // #3
}

根據編譯器和設置的優化級別, #1行和#2行打印的地址可能彼此不同,也可能不同。

但是,無論選擇何種編譯器或優化級別, #3行打印的 2 個地址總是彼此不同。

這是一個可以玩的演示

那么在每種情況下f返回的規則是什么?

C++ 中的兩個活動對象(幾乎)總是具有不同的地址。

由於#1 #2 中的臨時對象具有不重疊的生命周期,因此編譯器可以自由地將#1 的存儲重用於#2。

但是在#3 中,所有的臨時對象在表達式結束之前都是活動的(出於顯而易見的原因),在這種情況下,它們必須具有不同的地址。

除了“as if”規則之外,C++ 不支持對相同子表達式的保證緩存。 這意味着如果您不獲取地址,編譯器完全合理地存儲它們,但它喜歡或根本不存儲它們。

參考

N4861 Draft C++20 [6.7.9.2]除非 object 是位字段或大小為零的子對象,否則 object 的地址是它占用的第一個字節的地址。 如果一個對象嵌套在另一個對象中,或者如果至少一個是大小為零的子對象並且它們屬於不同類型,則兩個具有重疊生命周期且不是位域的對象可能具有相同的地址;否則,它們具有不同的地址並占用不相交的存儲字節。 ^28

在您的情況下,例外情況不適用。 腳注 ^28 也准確地說明了我上面寫的內容:

^28 :在“as-if”規則下,如果程序無法觀察到差異,則允許實現將兩個對象存儲在同一機器地址,或者根本不存儲 object。

編輯

來自@RiaD 的好問題:

但是這兩個 42 必須是不同的對象嗎? 例如,“abc”和“abc”可以是同一個數組。

行為取決於使用的文字類型,並在N4861 Draft C++20 5.13 [lex.literal]中精確定義。

  1. 字符串文字是所有文字類型中的一個例外,因為它們被歸類為左值,因此具有地址。

    [lex.string.14]評估字符串文字會產生字符串文字 object 和 static 存儲持續時間,從上面指定的給定字符初始化。 所有字符串文字是否不同(即存儲在不重疊的對象中)以及字符串文字的連續評估是否產生相同或不同的 object 未指定。

    這意味着文字可能具有與觀察到的@RiaD 相同的地址,但這與上述內容並不矛盾,因為它們是相同的 object。

  2. 所有其他文字,包括整數,都是純右值表達式,它們不是對象(從某種意義上說它們沒有地址),但在某些情況下,它們會通過foo(42)發生的臨時實現產生臨時 object 因為它是綁定的到一個const T& AFAIK標准沒有明確說相同的兩個純右值表達式必須產生不同的臨時,但它說一個表達式初始化一個臨時,所以我相信每個表達式都必須創建一個新的臨時,生命周期也略有不同。 因此,兩個地址(如果觀察到)必須不同。

臨時性一直持續到導致它們 spring 生命的完整表達式結束。

[類.臨時]

4 ... 臨時對象在評估完整表達式 ([intro.execution]) 的最后一步被銷毀,該完整表達式 ([intro.execution]) (詞法上)包含它們被創建的點。

這適用於所有臨時工。 這意味着在表達式 #3 中,假設它的評估結束時沒有拋出異常,兩個臨時對象的生命周期可能重疊。

除了少數例外(此處均不適用),兩個不同的對象在其生命周期內將具有不同的地址。

我以前的一些評論應要求在這里重新發布:

真正有趣的是 C++ 不要求對 object 的地址進行具體編碼。 (它沒有提到 function 的地址,順便說一句。)這是很自然的,因為 C++ 抽象機在大多數情況下對地址不感興趣。

兩個不同的對象只是......不是同一個對象,因為它們具有不同的身份 恆等的概念肯定被更廣泛地使用,例如左值,盡管它在大多數情況下也被小心地回避了。 如果對身份差異感興趣,規范只是規定了訪問對象的唯一允許方式(例如嚴格的別名規則),因為這里有多少對象被認為是實現細節。 地址在概念上是從對象的身份派生的,它不能幫助您使差異更加明顯。

依靠地址的概念來描述不同對象(及其子對象)之間的布局是合適的。 在這種特殊情況下,身份是不夠的。 這不是這里的情況(重疊的生命周期,而不是重疊的存儲)。 當涉及地址時,推理變得混亂。 正如所回答的那樣,由於 as-if 規則是有效的,當沒有可移植的方式來區分地址時,不同的對象可以具有相同的地址。 另請注意, addressof[[no_unique_address]]並不真正需要區分地址(而只是身份)。

暫無
暫無

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

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