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).
Related
Whenever we have a class with some static member variable, why do we need to define it?
Why can't we use it directly?
I wanted to see if any memory space would be allocated to the static variable if I don't define it, so I wrote this little code and it seems like memory is indeed allocated for the variable.
#include <iostream>
using namespace std;
class A
{
public:
int a;
static int b;
};
// int A::b = 1;
int main()
{
cout<<sizeof(A::b);
return 0;
}
Output:
4
Now, I defined the variable and initialized it (uncommented the int A::b = 1; line) and ran the same code, even this time the output was the same.
So, what is the purpose behind defining it?
The definition is required if the variable is odr-used, while sizeof(A::b) doesn't.
One and only one definition of every non-inline function or variable that is odr-used (see below) is required to appear in the entire program (including any standard and user-defined libraries). The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined.
For example, if you take address of the variable, then it's odr-used and it must be defined.
cout << &A::b;
For static data member you have to allocate memory for it in your implementation, what you are doing now does not allocate memory but you are just getting the size of the int.
In C++ 17 you can declare static variable inline, for int its default value is zero but you can set any value you want. Like this:
static inline int b=4;
Consider this example.
struct S
{
int j;
inline static int i;
int &ri{i};
};
S s;
static_assert(sizeof(s) > sizeof(int));
#include <type_traits>
static_assert(!std::is_standard_layout_v<S>);
( https://godbolt.org/z/vWFkBC ). The compiler reserves space for the reference within the class memory layout. I can't think of an example where a member reference which is initialized in its declaration would clearly be useful. Perhaps that is why compilers do not optimize for this case. Or, is there something in the Standard that prohibits optimizing out this reference?
In this class the storage is necessary to keep track at runtime of which object ri is bound to, for example:
int main()
{
int foo, bar;
S s = { 3, rand() % 2 ? foo : bar };
func(s); // in other translation unit
}
But even if you come up with some other exact case where the program could run without requiring storage for ri, it would mean that the size of the struct changes between different builds when the program undergoes some subtle change (or you use a different -O optimization flag) that makes the optimization no longer possible. This is generally not behaviour that programmers desire, so compilers don't do it.
Also the compiler has to take ABI compatibility into account; it's considered desirable by users for a header file to be used with a binary-only library built by one compiler and incorporated into a project using a different compiler. So the classes specified in the header should have a predictable layout.
You could make a similar argument that the compiler might not allocate storage for j so long as it determines the program does not use the value or address of j anywhere, and the response as to why the compiler doesn't actually do that
would be similar.
Here is my code:
#include <iostream>
class MyBaseClass
{
public:
static int StaticInt;
};
int MyBaseClass::StaticInt = 0;
template <int N> class MyClassT : public MyBaseClass
{
public:
MyClassT()
{
StaticInt = N;
};
};
template <int N> static MyClassT<N> AnchorObjT = {};
class UserClass
{
friend void fn()
{
std::cout << "in fn()" << std::endl; //this never runs
(void)AnchorObjT<123>;
};
};
int main()
{
std::cout << MyBaseClass::StaticInt << std::endl;
return 0;
}
The output is:
123
...indicating MyClassT() constructor was called despite that fn() was never called.
Tested on gcc and clang with -O0, -O3, -Os and even -Ofast
Question
Does this program have undefined behavior according to C++ standard?
In other words: if later versions of compilers manage to detect that fn() will never be called can they optimize away template instantiation together with running the constructor?
Can this code somehow be made deterministic i.e. force the constructor to run - without referencing function name fn or the template parameter value 123 outside of the UserClass?
UPDATE: A moderator truncated my question and suggested further truncation. Original verbose version can be viewed here.
Template instantiation is a function of the code, not a function of any kind of dynamic runtime conditions. As a simplistic example:
template <typename T> void bar();
void foo(bool b) {
if (b) {
bar<int>();
} else {
bar<double>();
}
}
Both bar<int> and bar<double> are instantiated here, even if foo is never invoked or even if foo is only ever invoked with true.
For variable template, specifically, the rule is [temp.inst]/6:
Unless a variable template specialization has been explicitly instantiated or explicitly specialized, the variable template specialization is implicitly instantiated when it is referenced in a context that requires a variable definition to exist or if the existence of the definition affects the semantics of the program.
In your function:
friend void fn()
{
(void)AnchorObjT<123>;
};
AnchorObjT<123> is referenced in a context that requires a definition (regardless of whether fn() is ever called or even, in this case, it is even possible to call), hence it is instantiated.
But AnchorObjT<123> is a global variable, so its instantiation means we have an object that is constructed before main() - by the time we enter main(), AnchorObjT<123>'s constructor will have been run, setting StaticInt to 123. Note that we do not need to actually run fn() to invoke this constructor - fn()'s role here is just to instantiate the variable template, its constructor is invoked elsewhere.
Printing 123 is the correct, expected behavior.
Note that while the language requires the global object AnchorObjT<123> to exist, the linker may still the object because there is no reference to it. Assuming your real program does more with this object, if you need it to exist, you may need to do more to it to prevent the linker from removing it (e.g. gcc has the used attribute).
"If later versions of compilers manage to detect that fn() will never be called [and] they optimize away template instantiation" then those compilers would be broken.
C++ compilers are free to implement any optimization that has no observable effect. In the situation you have outlined there would be at least one observable effect: namely a static class member does not get constructed and initialized, so a C++ compiler cannot completely optimize that away. It won't happen.
A compiler can ignore everything else about the function call, and not actually compile the function call itself, but the compiler must do whatever it needs to do to make arrangements so that the static class member gets initialized as if that function call was made.
If the compiler can determine that nothing else in the program actually uses the static class member, and removing it completely has no observable effect, then the compiler can remove the static class member, and the function that initializes it (since nothing else references the function).
Note, that even taking an address of a function (or a class member) would result in an observable effect, so even if nothing actually calls the function, but something takes the address of the function, it can't just go away.
P.S. -- all of the above presumes no undefined behavior in the C++ code. With undefined behavior entering the picture, all the rules go out the window.
The short answer is it works.
The long answer is it works unless the linker discards your entire translation unit (.obj).
This can happen when you create a .lib and link it. The linker typically picks which .obj to link from the lib based on a dependency graph of "do I use symbols that obj exports".
So if you use this technique in a cpp file, that cpp files has no symbols that are used elsewhere in your exexutable (including indirectly via other obj in your lib that are in turn used by the executable), the linker may discard yoir obj file.
I have experienced this with clang. We where creating self registering factories, and some where being dropped. To fix it we created some macros that caused a trivial dependency to exist, preventing the obj file from being discarded.
This doesn't contradict the other answers, because the process of linking a lib is aboit deciding what is and what is not in your program.
If a variable's intended scope is truly local, it would only make sense to me to keep it that way. This is what I have always done. However I recently switched from vim to eclipse at work and eclipse is flagging my constructor if every member variable is not initialized in the constructor. For example, in the code below, it compiles just fine. g++ has no problem with it. Eclipse on the other hand tells me that 'a' should be initialized in the constructor.
Is there any reason why this warning might be relevant or is it just worth ignoring all together?
class C
{
public:
C(){}
~C(){}
void foo();
};
void C::foo()
{
int a;
}
int main() {
C c;
return 0;
}
Eclipse on the other hand tells me that 'a' should be initialized in the constructor.
a cannot be initialized in the constructor because it's a local variable of the member function C::foo(). Eclipse is giving you a bogus warning.
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