可以在C++中优化未使用的数据成员吗

Can unused data members be optimized out in C++

本文关键字:未使用 数据成员 优化 C++      更新时间:2023-10-16

我有一个C++类,它有一个私有的未使用的char[],当该类在共享数组中使用时,严格地向该类添加填充以防止错误共享。我的问题有两个:

  1. 在某些情况下,编译器是否可以优化此数据成员?

  2. 使用-Wall编译时,如何使private field * not used警告静音?最好不要明确地沉默警告,因为我仍然想在其他地方看到这个问题的例子。

我写了一个小测试来检查我的编译器,这个成员似乎没有被删除,但我想知道标准是否允许这种优化。

填料.cc

#include <iostream>
class A {
 public:
  int a_ {0};
 private:
  char padding_[64];
};
int main() {
  std::cout << sizeof(A) << std::endl;
  return 0;
}

汇编

$ clang++ --version
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
$ clang++ -std=c++11 -O3 -Wall padding.cc
padding.cc:8:8: warning: private field 'padding_' is not used [-Wunused-private-field]
  char padding_[64];
       ^
1 warning generated.
$ ./a.out 
68

我不知道编译器优化,但可以通过两种方式消除警告:要么使用pragmas:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-private-field"
class A{
//...
};
#pragma clang diagnostic pop

或者,可能更适合你,在你的课上包括一个假朋友功能:

class A{
friend void i_do_not_exist();
//... 
};

这样,编译器就无法知道字段是否被使用。因此,它不会抱怨,也绝对不会扔掉任何东西。如果在任何地方定义i_do_not_exist()函数,这可能会导致安全问题,因为该函数被授予对类的私有成员的直接访问权限。

第三种解决方案是定义一个访问padding_成员的伪函数:

class A {
 private:
  void ignore_padding__() { padding_[0] = 0; }
  //... 
};

编译器可以执行一致程序无法检测到的任何更改。所以答案是肯定的。但是,一个对代码进行更改的编译器是一个糟糕的编译器。很可能,你没有使用一个糟糕的编译器。

我确信编译器不允许重新排序或删除数据成员,因此对于编写接受此类结构的API的任何人来说,.h文件都是自文档。他们只被允许使用简单且定义良好的填充规则,这样开发人员就可以很容易地从读取代码中推断出偏移量。

也就是说,为什么要对缓存大小和错误共享的可能性进行假设?缓存大小应该是编译器的责任,我怀疑真正的问题是试图在多个线程之间共享一个数组。在每个线程上本地更新结构,并只在末尾写出对共享数组的更改。

我怎样才能让";专用字段*未使用";使用-Wall编译时出现警告?

首先,您可以使用alignas来避免手动填充(如果值是2的幂):

class alignas(64) A
{
public:
  int a_{0};
};

演示

这不是你的例子:-/

因此,您可以使用属性[[maybe_unused]]使警告静音:

class A
{
public:
  int a_ {0};
private:
  [[maybe_unused]]char padding_[64];
};

演示