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:
Can this data member be optimized out by the compiler in some circumstances?
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
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; }
//...
};
The compiler can perform any change that can't be detected by a conforming program. So the answer is yes. But a compiler that makes changes that make your code worse is a lousy compiler. Odds are, you aren't using a lousy compiler.
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.
How can I silence the "private field * not used" warnings when I compile with -Wall?
First, you might used alignas to avoid manual padding
(if value is a power of 2):
class alignas(64) A
{
public:
int a_{0};
};
Demo
It is not the case of your example :-/
So you might use attribute [[maybe_unused]] to silent the warning:
class A
{
public:
int a_ {0};
private:
[[maybe_unused]]char padding_[64];
};
Demo
Related
Below is a simple example using a static member inside a template. If this is compiled with g++ / avr-g++ using the -fno-threadsafe-statics option, the compiler still generates guard variables. This is unnecessary in my opinion.
struct A {
A() {}
void foo() {}
};
template<typename T>
struct B {
static void foo() {
mTop.foo();
}
inline static T mTop;
};
int main() {
B<A>::foo();
}
Does anybody know how to disable the generation of an 8-Bytes guard variable?
Edit: if you remove the empty ctor (or a defaulted-ctor) in order to use the compiler-generated, no guards are created. And if you simple create a global variable of type A (should be conceptually equal to the above), also no guards are created.
From the docs, emphasis mine:
-fno-threadsafe-statics
Do not emit the extra code to use the routines specified in the C++ ABI for thread-safe initialization of local statics. You can use this option to reduce code size slightly in code that doesn’t need to be thread-safe.
The example program in the question doesn't have any local statics, so there's nothing for this flag to actually apply to. However, even if thread safety isn't necessary, statics do still need a guard variable so as to avoid multiple initialization. Can't get around that.
As in the question:
let's say I have a small piece of code like this:
#include <iostream>
using namespace std;
struct foo {
int a;
foo() : a(12) {};
};
int
main()
{
volatile foo x;
return 0;
}
compiled with g++ -g -O2 it turns out, that x initialization is optimized away.
That one however:
#include <iostream>
using namespace std;
struct foo {
volatile int a;
foo() : a(12) {};
};
int
main()
{
volatile foo x;
return 0;
}
calls the constructor.
If I try to use the variables inside the code, (ie. cout << foo.a << endl;) the assembly output is equivalent in both cases.
Do I get the following right, that:
In the first case, there's no access to the struct at all, so it gets optimized away completely.
In the second one, struct's field is indicated as the one possible to change also during the construction and for that reason foo() is called no matter what.
Added:
I've tried fiddling with the above code:
calling things like while(foo.a--); works as expected, it actually happens instead of being deleted/replaced by result during optimization, thus it seems the volatile is actually inherited, yet the ctor behaves in this strange (or at least unexpected at first) way.
EDIT number 2:
I checked it with clang and MSVC and it behaves the same way as in gcc.
My understanding is as follows (and I am not sure about it):
In C++ volatile keyword forces compiler not to optimize seemingly redundant loads and stores to memory, i.e. if you have such example code:
int x = 5;
x = 6;
It will not be changed to:
int x = 6;
This is because x could be pointing to some address in memory, that is read by others, while you don't read it really in your program (imagine that you are sending some configuration over USART to microcontroller by writing to certain memory address, and the microcontroller reads it's configuration from that address - if compiler was to optimize writes to this memory, then whole program would malfunction).
Another thing that one must remember is that when instance of a class is declared with volatile specifier, then its members inherit this specifier (as Igor Tandetnik pointed out in comment, referring to C++ Standard). But this is not the whole truth, because in order to get volatile behaviour, you would have to call member functions, that are marked as volatile - similar to marking member function as const (please see this: http://www.devx.com/tips/Tip/13671). Because AFAIK ctors/dtors cannot be marked with volatile keyword (as in Defining volatile class object), you would have to change your code a bit (perhaps invoking volatile member function from within ctor would do the thing, but this is only a guess).
I got 17 integer constants that I'd like to have as private in my class. Is it really necessary to use initialization list?
I read somewhere that I can assign values to constants in the header file, but it doesn't seem to work. I get this error message:
sorry, unimplemented: non-static data member initializers
Is it really necessary to use initialization list?
In modern (2011-era) C++, no. In older versions of the language, yes.
Your error message is apologising that your compiler doesn't support the new initialisation syntax for non-static members yet. Assuming you're using GCC (since I recognise that error from that compiler), then according to this page you'll need to upgrade to at least version 4.7 for that feature.
Alternatively, since they're private and constant, you might consider moving them out of the class into a local namespace in the class's implementation file. Of course, that will only work if you don't need to access them from any inline member functions.
Finally, if they have the same values for all instances of the class (which is likely, since they are const and you're able initialise them independently of the constructor arguments), you could declare them static. Then they can be initialised in their declaration (although older compilers might only allow that if they have an integer type). However, if they are odr-used (roughly speaking, if you need to take a pointer or reference to them), then they will also need to be defined in exactly one source file.
.h:
class MyClass {
public:
MyClass();
~MyClass();
int doSomething();
private:
const int m_newint = 1;
const int m_dosomething = 2;
};
.cc:
MyClass::MyClass() {}
MyClass::~MyClass() {}
int MyClass::doSomething() {
return m_dosomething;
}
Is valid C++11 code, make sure your compiler is set to -std=c++11 to use the
feature.
I couldn't find any information on Google about this, In the following example:
#include <iostream>
class Default
{
public:
void Print()
{
std::cout << "This is a message\n";
}
};
template <class C = Default>
class Template
{
public:
static void Test()
{
Default oDefault();
}
};
int main()
{
return 0;
}
the code fails to compile with the error:
In static member function ‘static void Template::Test()’:
19:22: error: default template arguments may not be used in function templates without -std=c++0x or -std=gnu++0x
The trouble is that it doesn't like the brackets appearing on that line and I don't understand why. If I remove the brackets the code compiles just fine. Also if I remove the template declaration (line 13) it also compiles just fine. Is this a bug or is there some rule somewhere about exactly this situation?
I'm using g++4.6.1 (gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3))
Change it to:
Default oDefault = Default(); // Version 1
Though you can use:
Default oDefault; // Version 2
This has a slightly different meaning.
Version 1: Causes the POD members to be zero initialized (in some situations).
Version 2: Causes the POD members to be un-initialized (in some situations).
Through version one looks like it invokes an extra copy construction this is not the case (in most compilers) as the extra copy will be elided by the compiler and a simple normal (zero-initialized) construction will happen.
You should prefer zero-initialization to default (in general) as if the class (or any members type) does not have a user defined constructor (Like Default) then the difference is that default-initialization leaves POD members undefined while zero-initialized leaves POD members initialized to zero. Now you may think now that my class has no members so it does not matter. But what happens if you modify the class are you going to go and find all instances and update them; Best to use version one and let the compiler do the correct thing.
For all the mind blowing details see:
https://stackoverflow.com/a/620402/14065
https://stackoverflow.com/a/1613383/14065
The reason your initial version did not work is that it is actually a forward declaration of a function. This is caused by the complex syntax of C++ and just one of the rules you need to remember. You can look this up as "The Most Vexing Parse".
Default oDefault();
The compiler sees this as an function declaration and not as creating an object.
It declares a function oDefault() which takes no parameters and returns a Default object.
Change it to:
Default oDefault;
I was trying out the validity of private access specifier in C++. Here goes:
Interface:
// class_A.h
class A
{
public:
void printX();
private:
void actualPrintX();
int x;
};
Implementation:
// class_A.cpp
void A::printX()
{
actualPrintX();
}
void A::actualPrintX()
{
std::cout << x:
}
I built this in to a static library (.a/.lib). We now have a class_A.h and classA.a (or classA.lib) pair. I edited class_A.h and removed the private: from it.
Now in another classTester.cpp:
#include "class_A.h" // the newly edited header
int main()
{
A a;
a.x = 12; // both G++ and VC++ allowed this!
a.printX(); // allowed, as expected
a.actualPrintX(); // allowed by G++, VC++ gave a unresolved linker error
return 0;
}
I know that after tampering a library's header all bets are off (I mean, system integrity, etc.) Albeit the method being hacky, is this really allowed? Is there a way to block this? Or am I doing something wrong here?
private is not a security mechanism. It's a way of communicating intents and hiding information that other parts of your program do not need to know about, thus reducing overall complexity.
Having two different header files is not standards compliant, so technically you're entering undefined behaviour territory, but practically, as you've found, most compilers won't care.
You've strayed beyond what's allowed in C++, so what you're doing isn't allowed - but of course it may work on some compilers in some situations.
Specifically, you're violating the One Definition Rule.
This article by Herb Sutter explains it quite nicely - it also provides a legal and portable way of circumventing the access specifier system.
No. The private access control is there to stop YOU from doing stupid things, not as a security mechanism to stop others accessing your data or functions. There are many, many ways of getting around it.
I tried. This is an nm of a program I wrote having a class Test with one private method and a public one.
0000000100000dcc T __ZN4Test3barEv
0000000100000daa T __ZN4Test3fooEv
As you can see, the signature is exactly the same. The linker has absolutely nothing to distinguish a private method from a public one.
I agree with most of the other answers.
However, I'd like to point out that it is perfectly acceptable for a compiler to physically arrange the members differently when you remove that private. If it works, that is luck. You can't count on it. If both sides aren't using the same declaration, they aren't really using the same class.
There is no A::actualPrintX implementation anywhere. That is your linker error.
Since noone has mentioned a way to block this... One possible way to block access to private members, is to declare them as a separate internal type not visible outside the file. Of course, if you want to provide explicit access to this internal, you would then have to provide the internal declaration. That's also commonly done using an internal header containing that type.
Note: You'll have to keep track of allocating/freeing that internal object in this example. There are other ways of doing it that don't require this.
// class_A.h
class A {
public:
void printX();
private:
void *Private;
};
// class_A.cpp
class A_private {
void actualPrintX();
int x;
};
void A::printX() {
reinterpret_cast<A_private *>(Private)->actualPrintX();
}
void A_private::actualPrintX() {
std::cout << x:
}
In most cases you don't even have to edit header file to make private members public. You can do this with preprocesor. Something like this:
//"classWithPrivateMembers.hpp"
class C
{
private: //this is crucial for this method to work
static int m;
};
int C::m = 12;
and then, this will work:
#define private public
#include "classWithPrivateMembers.hpp"
#undef private
int main()
{
C::m = 34; // it works!
}
Bear in mind also that when you change a member variable's access, the compiler may place it at a different offset within the class object. The standard allows compilers a fair amount of freedom in rearranging members (at least within the same access level, I think).