Since C++17, I've been experimenting easier ways to get class static variables. I'm writing a header-only library. Apparently the new meaning of inline
for variables is suited for this.
class thingy {
static inline reporter rep;
};
But I've been getting runtime errors.
I'm using Visual Studio 15.6.4
To test, the following:
thingy
has a static member variablefoo.h
#pragma once
#include <iostream>
using namespace std;
struct reporter {
reporter() {
cout << "reporter() - " << this << endl;
}
~reporter() {
cout << "~reporter() - " << this << endl;
}
};
class thingy {
static inline reporter rep;
};
main.cpp
#include "foo.h"
int main() {}
foo.cpp
#include "foo.h"
Most disappointingly, it prints:
reporter() - 00007FF670E47C80
reporter() - 00007FF670E47C80
~reporter() - 00007FF670E47C80
~reporter() - 00007FF670E47C80
As you can see, it is constructed twice and destructed twice at the same location - not good.
Am I misunderstanding what inline
on variables is for?
Is there another way to get class statics in header only? Has this changed in C++17?
Yes there is difference between declaring a static variable as global and local. If it is local, it can be accessed only in the function where it's declared. But if it is global, all functions can access it.
You can't define a static member variable more than once. If you put variable definitions into a header, it is going to be defined in each translation unit where the header is included. Since the include guards are only affecting the compilation of one translation unit, they won't help, either.
For the static variables, we have to initialize them after defining the class. To initialize we have to use the class name then scope resolution operator (::), then the variable name. Now we can assign some value.
3.1. Static variables in C have the following two properties: They cannot be accessed from any other file. Thus, prefixes “ extern ” and “ static ” cannot be used in the same declaration. They maintain their value throughout the execution of the program independently of the scope in which they are defined.
It looks like a bug in VS2017.
A few relevant bug reports can be found, although they do not exactly meet your case:
This will be addressed in 15.7 - thanks for the report! Combining multiple guards for adjacent static variables into a single guard is a backend optimization which can go wrong when inlining under certain circumstances. That's basically the issue here.
Hopefully this static variable when inline-ed bug will be fixed soon in their next patch.
Meanwhile, I found that compiling in Release Mode
makes your reporter
initialized only once as expected, while in Debug Mode
this bug occurs for their backend optimization.
So I guess this won't be going into your products, at least.
It's a bug in MSVC.
The static class member thingy::rep
, like thingy
, has external linkage, the inline
specifier doesn't change that.
As such, there can be only one instance of it in the whole program, and as such it can only be initialized once.
[class.static.data]/5:
Static data members of a class in namespace scope have the linkage of that class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With