Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can unused data members be optimized out in C++

Tags:

c++

memory

I have a C++ class which has a private unused char[] strictly to add padding to the class to prevent false sharing when the class is used in a shared array. My question is 2-fold:

  1. Can this data member be optimized out by the compiler in some circumstances?

  2. How can I silence the private field * not used warnings when I compile with -Wall? Preferably, without explicitly silencing the warning as I still want to catch instances of this issue elsewhere.

I wrote a little test to check for my compiler, and it seems that the member isn't removed, but I want to know if the standards allow this sort of optimization.

padding.cc

#include <iostream>

class A {
 public:
  int a_ {0};

 private:
  char padding_[64];
};

int main() {
  std::cout << sizeof(A) << std::endl;
  return 0;
}

compilation

$ 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
like image 787
Cookyt Avatar asked Apr 19 '14 23:04

Cookyt


2 Answers

I don't know about the compiler optimizations, but you can get rid of the warnings in two ways: Either use pragmas:

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

or, which is probably better suited for you, include a fake friend function in your class:

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

In that way, the compiler cannot know if the field is used or not. Therefore, it does not complain and will definitely not throw anything out. This can lead to safety issues if the i_do_not_exist() function is ever defined anywhere, as that function is given direct access to the private members of the class.

A third solution is to define a dummy function which access the padding_ member:

class A {
 private:
  void ignore_padding__() { padding_[0] = 0; }
  //... 
};
like image 131
Roberto Avatar answered Oct 03 '22 05:10

Roberto


I'm pretty sure compilers aren't allowed to reorder or remove data members, so the .h files are self-documenting for anyone writing an API that accepts such a struct. They're only allowed to use simple and well-defined padding rules so developers can easily infer the offsets just from reading the code.

That said, why are you making assumptions on the cache size and the likelihood of false sharing? The cache size should be the compiler's responsibility, and I suspect the real issue is trying to share an array between multiple threads. Update the struct locally on each thread and only write out the changes to the shared array at the end.

like image 43
BonzaiThePenguin Avatar answered Oct 03 '22 04:10

BonzaiThePenguin