c++ - 为什么 [[no_unique_address]] 属性在某些情况下不起作用?

标签 c++ c++20

我正在玩弄 [[no_unique_address]] C++20 中引入的属性。据我了解cppreference article和标准的 dcl.attr.nouniqueaddr 章节,此属性指示该字段不需要具有不同于该类的所有其他非静态数据成员的地址。因此编译器可以优化结构的内存布局。但有一件事让我感到困惑。

考虑以下示例 ( https://godbolt.org/z/fj6nGebcs ):

struct Empty {};
struct Test {
  [[no_unique_address]] Empty em1;
  char f1;
  int f2;
  [[no_unique_address]] Empty em2;
};

字段 em1 的大小为零,将位于与 f1 相同的地址。 对我来说,同样的优化可以应用于 em2 并且它将具有与 f2 相同的地址和零大小似乎是合乎逻辑的。但它不是那样工作的。经过一些实验,我可以说如果在结构末尾定义了一个带有 [[no_unique_address]] 的字段,这种优化根本不起作用。所以用最新版本的 gcc 和 clang 编译,struct Test 的大小将为 12(1 字节 char 字段,3 字节对齐,4 字节 int 字段,以及大小为 1 字节和 3 字节对齐的 struct Empty 字段)。

现在让我们将 em2 向上移动 ( https://godbolt.org/z/Goz9Tj66K ):

struct Empty {};
struct Test {
  [[no_unique_address]] Empty em1;
  char f1;
  [[no_unique_address]] Empty em2;
  int f2;
};

此更改后,struct Test 的大小将为 8,并且 em2 字段将具有与 f2 相同的地址。

我不明白为什么会这样。我在 clang 中找到了相同结构大小的测试.最新的 gcc 以同样的方式工作。

但我不确定,为什么编译器不能像第二个例子那样在上面的第一个例子中应用 [[no_unique_address]] 优化。 有任何技术限制吗?还是跟编译器内部实现有关?

最佳答案

[[no_unique_address]] 的行为始终由编译器决定;它永远不需要做任何事情。编译器可以在所有情况下忽略它,在某些情况下尊重它而在其他情况下忽略它,或者一直尊重它。只要编译器不是随机执行(即:它是一致的),它就可以执行任何它想执行的操作(在其他布局规则内)。

那么为什么它在一种情况下有效而在另一种情况下无效呢?因为这就是编译器供应商实现它的方式。

如果您想充分利用它,请让编译器最容易处理。不要多次使用相同的空类型(这会限制编译器的功能)。首先声明所有空字段。

或者,您必须跟踪编译器正在使用的 ABI 规则。 Itanium ABI在 Linux 上使用对 no_unique_address 有特殊规定。

关于c++ - 为什么 [[no_unique_address]] 属性在某些情况下不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67722527/

相关文章:

c++ - std::async 使用同一个线程,我的代码没有实现并行。

c++ - 功能访问限制

co_await 表达式中的 c++ coroutines temporaries

c++ - 为什么概念细化不能使用简洁的语法

c++ - 使用临时数组作为左值

c++ - 对象标识符、返回值或变量?

c++ - 在 C 中使用 32 位整数的未使用内存

c++ - 在概念约束中使用变量模板会产生编译错误

c++ - 在 C++17 或更新版本中在哪里初始化静态常量成员?

c++ - 在 C++20 中移动 vector