繁体   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