std::construct_at 是否使联合的数组成员处于活动状态?

2024-03-31

看这个例子(godbolt https://godbolt.org/z/fh888f5ab):

#include <memory>

union U {
    int i[1];
};

constexpr int foo() {
    U u;
    std::construct_at(u.i, 1);
    return u.i[0];
}

constexpr int f = foo();

gcc 和 msvc 成功编译了这个,但 clang 抱怨:

常量表达式中不允许构造没有活动成员的联合体成员“i”的子对象

哪个编译器是正确的?我认为 clang 在这里是错误的,因为 C++20 隐式创建对象(P0593 http://wg21.link/p0593)应该使这个程序有效(因为应该隐式创建数组,这应该使u.i活跃),但我不确定。


U u;

不开始的生命周期i子对象。开始除数组类型之外的变量的生命周期char, unsigned char or std::byte也不是特别有资格的操作之一隐式创建对象. [基本.介绍.对象]/13 https://timsong-cpp.github.io/cppwp/n4868/basic#intro.object-13

因此此时i成员绝对不活动并且数组对象不活动。

正如@Sebastian 在问题评论中提到的,调用std::construct_at on u.i那么在常量表达式中不允许使用,因为[expr.const]/6.1 https://timsong-cpp.github.io/cppwp/n4868/expr.const#6.1特别要求提供的指针指向一个对象,该对象的生命周期开始于常量表达式的求值期间(或者是从std::allocator).

因此,Clang 对我来说似乎是正确的。有一个针对此问题的开放 GCC 错误here https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102286.

但我不确定这是否是预期的解释,因为如果成员使用非数组类型,Clang 确实接受该程序,根据我的推理,这同样是不允许的。

相关措辞是以下结果的结果this https://github.com/cplusplus/nbballot/issues/43评论。

无论如何,隐式对象创建并不打算发生在常量表达式中,尽管目前看来是这样的(question https://stackoverflow.com/questions/70556755/does-implicit-object-creation-apply-in-constant-expressions), see CWG 问题 2469 https://wg21.cmeerw.net/cwg/issue2469.

如果没有如下所述的隐式对象创建,则在需要常量表达式的上下文中的使用应该是格式错误的,独立于std::construct_at限制和以下考虑因素。


如果在常量表达式上下文之外使用,该构造是否具有定义的行为,我并不完全确定。

但我认为std::construct_at被指定为相当于新表达意味着它将调用operator new,指定在它返回的存储中隐式创建对象。[基本.介绍.对象]/13 https://timsong-cpp.github.io/cppwp/n4868/basic#intro.object-13

Whether operator new必须是一个分配operator new我并不完全清楚是否要求这是真的。我认为“在返回的存储区域中”的措辞不需要它。

i属于类型int[1],这是一个隐式生命周期类型,如果需要,可以通过有资格隐式创建对象的操作隐式创建它们。[基本.类型.一般]/9 https://timsong-cpp.github.io/cppwp/n4868/basic#types.general-9

因此我认为construct_at将隐式创建一个数组对象u.i并开始它的生命周期。我也认为[基本.介绍.对象]/2 https://timsong-cpp.github.io/cppwp/n4868/basic#intro.object-2将保证该对象成为联合的子对象,以便u.i会参考它。

然而,考虑到操作的存储只有单个的大小int并假设这也是中的存储[基本.介绍.对象]/13 https://timsong-cpp.github.io/cppwp/n4868/basic#intro.object-13,只有长度的数组1可以在其中隐式创建。因此如果i长度大于1,隐式创建的数组不能与成员完全重叠,因此不能成为联合的子对象。

在这种情况下,隐式对象创建无法进行return u.i[0];定义的行为。


有一个关于这个问题的讨论here https://lists.isocpp.org/std-proposals/2021/09/3171.php这似乎表明已经形成了指向第一个元素的指针u.i在其生命周期之外是 UB,在这种情况下construct_at带数组的版本会更直接地具有 UB,但至少编译器接受两者auto x = u.i; and auto x = &u.i[0];不断地表达,没有抱怨。正如该答案的评论中提到的,这似乎也是错误的。


总而言之我认为std::construct_at一般可以not用于激活数组成员union.


但是,假设您更换std::construct_at打电话给

u.i[0] = 1;

然后这个赋值将开始数组对象的生命周期,如中所述[class.union.general]/6 https://timsong-cpp.github.io/cppwp/n4868/class.union#general-6。从 C++20 开始,这对于常量表达式也没有被取消资格。因此,如果在需要常量表达式的上下文中使用,代码不会格式错误,也不会在该上下文之外具有未定义的行为。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

std::construct_at 是否使联合的数组成员处于活动状态? 的相关文章

  • ASP.NET MVC 中的经典 ASP (C#)

    我有一个应用程序想要 最终 转换为 ASP NET MVC 我想要进行全面的服务升级 到 ASP NET 但想要使用当前的 ASP 内容来运行当前的功能 这样我就可以在对新框架进行增量升级的同时升级小部分 该站点严重依赖于不太成熟的 VB6
  • OpenCv读/写视频色差

    我试图简单地使用 openCV 打开视频 处理帧并将处理后的帧写入新的视频文件 我的问题是 即使我根本不处理帧 只是打开视频 使用 VideoCapture 读取帧并使用 VideoWriter 将它们写入新文件 输出文件看起来比输入更 绿
  • 显示异常时的自定义错误消息:从客户端检测到潜在危险的 Request.Form 值

    我在我的 Web 应用程序中使用 ASP NET 的登录控件 当发生此异常时 我想在标签上显示一种有趣的错误类型System Web HttpRequestValidationException A potentially dangerou
  • 从多个类访问串行端口

    我正在尝试使用串行端口在 arduino 和 C 程序之间进行通信 我对 C 编程有点陌生 该程序有多种用户控制形式 每一个都需要访问串口来发送数据 我需要做的就是从每个类的主窗体中写入串行端口 我了解如何设置和写入串行端口 这是我的 Fo
  • 访问者和模板化虚拟方法

    在一个典型的实现中Visitor模式 该类必须考虑基类的所有变体 后代 在许多情况下 访问者中的相同方法内容应用于不同的方法 在这种情况下 模板化的虚拟方法是理想的选择 但目前这是不允许的 那么 模板化方法可以用来解析父类的虚方法吗 鉴于
  • 检查算术运算中的溢出情况[重复]

    这个问题在这里已经有答案了 可能的重复 检测 C C 中整数溢出的最佳方法 https stackoverflow com questions 199333 best way to detect integer overflow in c
  • ASP MVC:服务应该返回 IQueryable 的吗?

    你怎么认为 你的 DAO 应该返回一个 IQueryable 以便在你的控制器中使用它吗 不 您的控制器根本不应该处理任何复杂的逻辑 保持苗条身材 模型 而不是 DAO 应该将控制器返回给视图所需的所有内容 我认为在控制器类中看到查询 甚至
  • 如何从网站下载 .EXE 文件?

    我正在编写一个应用程序 需要从网站下载 exe 文件 我正在使用 Visual Studio Express 2008 我正在使用以下代码 private void button1 Click object sender EventArgs
  • 即使手动设置显示环境变量后,WSL Ubuntu 也会显示“错误:无法打开显示”

    我在 WSL Ubuntu 上使用 g 我使用 git 克隆了 GLFW 存储库 使用了ccmake命令配置并生成二进制文件 然后使用make在 build 目录中最终创建 a文件 我安装了所有OpenGL相关的库 usr ld 我不记得我
  • 如何在c#中的内部类中访问外部类的变量[重复]

    这个问题在这里已经有答案了 我有两个类 我需要声明两个类共有的变量 如果是嵌套类 我需要访问内部类中的外部类变量 请给我一个更好的方法来在 C 中做到这一点 示例代码 Class A int a Class B Need to access
  • 在 C 中使用 GNU automake 中的解析器

    我是 GNU autotools 的新手 在我的项目中使用了 lex 和 yacc 解析器 将它们作为 makefile am 中的源代码会产生以下错误 配置 in AC CHECK PROGS YACC bison yacc none i
  • 当我“绘制”线条时,如何将点平均分配到 LineRenderer 的宽度曲线?

    我正在使用线条渲染器创建一个 绘图 应用程序 现在我尝试使用线条渲染器上的宽度曲线启用笔压 问题在于 AnimationCurve 的 时间 值 水平轴 从 0 标准化为 1 因此我不能在每次添加位置时都在其末尾添加一个值 除非有一个我不知
  • 如何挤出平面 2D 网格并赋予其深度

    我有一组共面 连接的三角形 即二维网格 现在我需要将其在 z 轴上挤出几个单位 网格由一组顶点定义 渲染器通过与三角形数组匹配来理解这些顶点 网格示例 顶点 0 0 0 10 0 0 10 10 0 0 10 0 所以这里我们有一个二维正方
  • 有没有一种简单的方法可以让 Visual Studio 2015 使用特定的 ToolsVersion?

    使用特定版本构建项目或解决方案时msbuild我可以使用以下命令选择早期的 net 工具链 toolsversion or tv switch C Program Files x86 MSBuild 14 0 bin msbuild tv
  • 在类的所有方法之前运行一个方法

    在 C 3 或 4 中可以做到这一点吗 也许有一些反思 class Magic RunBeforeAll public void BaseMethod runs BaseMethod before being executed public
  • 为什么拆箱枚举会产生奇怪的结果?

    考虑以下 Object box 5 int int int box int 5 int nullableInt box as int nullableInt 5 StringComparison enum StringComparison
  • strcmp 给出分段错误[重复]

    这个问题在这里已经有答案了 这是我的代码给出分段错误 include
  • 转到定义:“无法导航到插入符号下的符号。”

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 我今天突然开始在我的项目中遇到一个问题 单击 转到定义 会出现一个奇怪的错误 无法导航到
  • 带重定向标准流的 C# + telnet 进程立即退出

    我正在尝试用 C 做一个 脚本化 telnet 项目 有点类似于Tcl期望 http expect nist gov 我需要为其启动 telnet 进程并重定向 和处理 其 stdin stdout 流 问题是 生成的 telnet 进程在
  • 错误:无效使用不完整类型“类 Move”/未定义对 Move::NONE 的引用

    拜托 我不知道为什么这个简单的代码被拒绝 它给了我 2 个编译错误 请帮帮我 I use 代码 块 20 03 我的编译器是GNU GCC 移动 hpp class Move public Move Move int int public

随机推荐