【问题标题】:Is it well defined to reference a variable before it's constructed在构造变量之前是否定义好引用变量
【发布时间】:2020-04-15 01:14:04
【问题描述】:

这在精神上类似于为c 询问和回答的question。那里的 cmets 暗示 c++ 的精确答案会有所不同,所以这里有一个类似的问题,适用于 c++ 中编写的代码。

下面的程序定义好了吗?

int f(int& b) 
{ 
  b = 42; 
  return b; 
}

int a { f(a) };

对我来说似乎没问题,但另一方面,a 是如何从由函数计算的值构造的,它本身会修改 a?我对此有一种鸡与蛋的感觉,所以解释一下会很好。对于它的价值,它appears 工作。

这似乎是同一个问题,所以这里;对于类类型和基本类型,答案是否会有所不同。即下面的格式是否正确?

struct S { int i; };

S f(S& b) 
{ 
    b.i = 42; 
    return b; 
}

S a { f(a) };

同样,不管它的价值,这个appears 也可以工作。

【问题讨论】:

  • 我不确定,因此是评论而不是答案,但我的猜测可能是它始终是 UB,或者它仅适用于基本类型。
  • 是的,这是合法的。 SO上有这样的问题。让我们搜索一下。
  • @DanielH 好的,在这种情况下,我已将问题编辑得更准确。
  • @S.M.那很好啊。不过我没找到。
  • 我记得几个月前读过同样的问题;从内存中它曾经是合法的,但不再是 C++20

标签: c++ language-lawyer


【解决方案1】:

这种行为在 C++20 中似乎是未定义的。更改由 P1358 进行,解决了 CWG 2256。由于缺陷解决方案通常具有追溯性,因此该代码在所有 C++ 版本中都应视为 UB。

根据[basic.life]/1

...T 类型对象的生命周期开始于:

  • 获得了与 T 类型正确对齐和大小的存储,并且
  • 其初始化(如果有)已完成(包括空初始化)...

在调用f(a) 的时候,对象a 还没有开始它的生命周期,因为它的初始化还没有完成。根据[basic.life]/7

类似地,在对象的生命周期开始之前,但在分配对象将占用的存储空间之后......任何引用原始对象的glvalue都可以使用,但只能以有限的方式使用。 ...如果出现以下情况,则程序具有未定义的行为:

  • glvalue 用于访问对象...

因此,在初始化完成之前写入a 是UB,即使存储空间已经分配。

【讨论】:

  • 所以,澄清一下,这里的类类型和基本类型没有区别?
  • 与问题无关,如果没有启动对象的生命周期,怎么会有“原始对象”?
  • @cigien • 原始基本类型是对象,就像类类型是对象一样。对象生命周期没有区别。
  • @Eljay 好的,有道理。在这个问题的回答是否定的之后,我对任何事情都不太确定了:p
  • @cigien 对于类类型的对象,规则要宽松一些。在构造函数运行时,生命周期尚未开始,但您仍然可以通过某些方式访问该对象(例如,您可以访问其 mem-initializers 已经完成的成员)。但是,此例外不适用于您的 S 示例,因此它也是 UB。
猜你喜欢
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
  • 2012-01-20
  • 2018-05-25
  • 2013-02-28
  • 2012-10-29
  • 1970-01-01
  • 2021-12-23
相关资源
最近更新 更多