TL;DR : I need global objects to be initialized at compile time, and I cannot use constexpr constructors. Can I use aggregate initializers for this task?
I know that C/C++ aggregate initializers can be used to initialize an object's public members like this :
MyObj obj = { "object1", 3, 7.2F };
I discovered their existence not long ago, and I thought about a previous issue I had.
I have a global object with a class type which I'm currently initializing using a constructor :
MyObj obj = MyObj("object1", 3, 7.2F);
This constructor only sets a few members with the given arguments. The problem is that I'd like the object's members to already be initialized inside the application's executable (like a compile-time constructor), which is not the case. Yes, I have inspected the resulting binary file, and the object's space is zeroed.
I cannot use constexpr on the constructor, because I'm working without modern C++ and have no way to upgrade.
This is why I'd like to know if I can use aggregate initializers to solve my issue.
EDIT 1 : I forgot to mention that I am developing for Windows, and that the objects I want to initialize have the __declspec(dllexport) and extern "C" specifiers.
As n. 1.8e9-where's-my-share m. said, the terms "compile-time" and "run-time" are meaningless as far as the language is concerned. They are more likely to concern the toolset you're working with.
Best answer I can give here is "uncertain". The behavior of aggregate initializers is not part of the C++ standard, which means it is implementation-defined.
To answer my problem, the best bets I have are either switching to modern C++ and use constexpr constructors, or writing my data in ASM files.
Related
I have a situation like this:
class A {
public:
A() : n(0) {}
private:
int n;
int m;
}
There is simply no meaning in the application logic to initialize m in the constructor. However, Eclipse warns me that the constructor leaves m uninitialized. I can't run the code somewhere else now. The warning is:
Member 'm' was not initialized in this constructor
So, does C++ encourage us to initialize all the data members in the constructor or it is just Eclipse's logic?
Should constructor initialize all the data members of the class?
That would be a good practice.
So, does C++ encourage us to initialize all the data members in the constructor?
It's not required by the c++ standard. As long as you initialize all variables before they're used, your program is correct in that regard.
or it is just Eclipse's logic?
Quite likely. Neither g++ nor clang versions that I tested warn about this when all warnings are enabled. The logic may or might not be based on high integrity c++ coding standard
12.4.2 or some other coding standard or style guide.
C++ doesn't require attributes to be initialized in constructor, except in case of const attributes where there value must be defined in initialization list.
However, it is clearly a good practice to initialize every attributes in constructor. I cannot count how many bugs I've met due to a non initialized variable or attributes.
Finally, every object should permanently be in a consistent state, which include both public (accessible) attributes and private attributes as well. Optimization should not be a reason for keeping an object un-consistent.
Fully disagree with all the answers and comments. There is absolutely no need to default initialze a member when it is not needed. This is why C/C++ never initializes built-in types as members or automatic variables - because doing so would impede performance. Of course, it is not a problem when you create your object/variable once (that's why statics are default-initialized), but for something happening in a tight loop default initialization might eat valuable nanoseconds.
The one exception to this rule would, in my view, be pointers (if you happen to have raw pointers in your code). Raw pointers should be NULL-initialized, since having invalid pointer is a direct way to undefined behaviour.
For completeness, the warning comes from the C/C++ Code Analysis. In particular the problem is Potential Programming Problems / Class members should be properly initialized
To change the code analysis settings (in this case I recommend per-project) edit the project properties. You can disable the whole warning, or disable it on just the files that violate the warning condition.
As for comparing CDT with GCC or CLang, this appears to be a case where additional code analysis is being done by CDT compared to what is available from the compilers. Of course that is to be expected as the CDT Code Analysis' remit is greater than that of the compiler.
PS, If you are up for it, you can read the implementation of this particular checker.
As it has been already said, you should always initialize pointers and of course const objects are mandatory.
In my opinion you should not initialize when it is not necessary but it is good to check for all non constructor initialized variables once in a while because they are source of very frequent and hard to find bugs.
I run Cppcheck every few months. This gives me more than one hundred 'false' warnings like "Member variable 'foo::bar' is not initialized in the constructor." but once in a while it discovers some real bugs so it is totally worth it.
can someone explain to me why cant i initialize a static variable inside the class ? what happens in compilation time exactly ?
for example :
class Object {
static int numberOfObjects = 0; // This gives the error
Object(){
nummberOfObjects++;
}
};
Thanks !
It's just a rule from the standard that was implemented by the compiler. The fact that it was a rule doesn't mean the opposite isn't possible, as the change in the newer C++11 standard and according compilers show.
In versions of C++ prior to C++11, the language standard simply doesn't allow you to perform a static variable definition inside the class declaration. In other words, You can't initialize it because it isn't constant. Since it can change during execution, the compiler needs some memory allocated somewhere to actually keep the value in. Since this is a class declaration, it doesn't actually allocate the memory for you. This issue doesn't exist for const values because they don't need memory assigned -- they are effectively "hard coded" just like if you replaced them with literals (or an old 'C' style #define).
You need a line of code outside of the class declaration that basically says:
int Object::numberOfObjects = 0;
This line isn't just initializing the static class variable, it's actually allocating a static int that will be used to store the value. The line of code up in the class declaration doesn't do this -- it merely tells the compiler that such a value exists somewhere.
Note that starting with C++11 this behavior is different. The language is now smart enough to figure out that you DO want to that memory defined, so you no longer need to do so manually.
In C++, classes constructors can use initialization lists, which I am told is a performance feature that improves by avoiding extra assignments. So I wonder if there is a similar approach to achieve the same benefits in C for functions that basically serve the same purpose to initialize structs as C++ class constructors?
I am a little unclear on how exactly the feature works in a C++ compiler, so any additional info on the subject will also be appreciated.
C doesn't have any similar feature, however since C also doesn't have constructors, there is no danger of unnecessary assignments.
The bigger principle is that introducing one feature into a language often creates a need for additional features to reinforce the original. An trivial example is threads. If threads are built into the language as a feature, then there is the immediate question of how to synchronize them. Hence synchronization is also needed. So you see languages (like C) with no built-in threads or synchronization and languages with both, but not one without the other. Here, constructors is to threads as synchonization is to list initializers.
In C++ constructors, initialization lists allow the C++ compiler to constructor members in-place, at the location of the member variable, instead of using an assignment operator, copy-constructor, or move-constructor to initialize the member variable. See Section 10.6 of the C++ FAQ for more details.
In C, there are no such automatic operations provided by the C compiler. This means that the programmer controls all initialization directly, and no special-language features are required to avoid these extra operations.
To be a little more clear, consider what happens when you use assignment to initialize in a C++ constructor:
The member variable is first constructed with a default constructor
A temporary object is constructed
An assignment or move-assignment operator is called to re-initialize the member variable with the temporary.
Call the destructor on the temporary.
While some compilers can optimize this away in some situations, your mileage may vary, and no C++ compiler can optimize these steps away in all situations. Now, consider how a programmer would exactly duplicate these steps in C:
void my_struct_init(struct my_struct* sp)
{
member_init_default(&sp->the_member); /* default constructor for member */
struct member memb; /* temporary on stack */
member_init_other(&memb, ...params...); /* initialize memb */
member_assign(&sp->the_member,&memb); /* assign member */
member_finalize(&memb); /* finalize the temporary */
}
Few C programmers would do this (without good reason). Instead, they would automatically code the optimization:
member_init_other(&sp->the_member, ...params...);
The feature exists in C++ because the compiler does a lot of automatic things for the programmer. This is often makes life easier for the programmer, but requires features like initialization lists to help the compiler generate optimum code. C compilers present a much simpler model of the underlying machine, do fewer things automatically, and thus require fewer features (though not necessarily less work) to generate similarly optimal code.
There is no such feature in C. The closest thing is designated initializers.
You can write a separate function and call it when you are creating an object from a class and then pass it to it:
C:
typedef struct {
int x;
}mine;
void mine_initializer(mine* me)
{
me->x = 4; //initialization
}
int main(void)
{
mine me;
mine_initializer(&me);
return 0;
}
Also you can do that in C++:
struct mine{
int x;
void initialize()
{
x = 4; //initialization
}
};
void main(void)
{
mine me;
me.initialize();
printf("%d",me.x);
}
this will output 4 as the result.
According to this question, Visual C++ 2005 (and also 2008/2010) does not zero initialize correctly data members.
Since I have a code which requires the standard behaviour, and which crashes in release mode (and not in debug), I suspect the issue comes from here.
Now, the problem is that the code base is quite large, and manually inspecting classes is difficult.
Is there a compiler option to trigger a warning on this non standard behaviour of MSVC ? With /W4, you get the warnings about some non standard extensions (conversions from rvalues to references, missing typename keyword), but not for this particular problem.
EDIT: I suspect code like that to cause trouble (pasted from the linked question)
include <cassert>
struct B { ~B(); Foo* m; };
int main()
{
B * b= new B();
assert ( b->m ==0);
}
in other portions of the code I have things like
B* b = new B();
and then, later,
if (b->m) { b->m->bar(); }
and b->m should be zero per the standard, but it's likely not (except in debug mode). I would like to detect such code (like a warning "m used without being initialized" or something)
Is this about foo::foo () : member () { }? Paste some example (code) of the problem you are seeing. In standard C++ implementation, the member should have value 0 (assuming it is of a fundamental type). However some older compilers do not do/implement this correctly and just leave it uninitialized. AFAIK there is no warning for this. You will have to go through the code and initialize the member with 0 or other value explicitly.
asper charles comment below, the compiler should be zero init before the ctor is called.
8.5 An object whose initializer is an empty set of parentheses, i.e., (), shall be
value-initialized. ... Value-initialization for such a class object may be implemented
by zero-initializing the object and then calling the default constructor
12.1/7 A non-user-provided default constructor for a class ... performs the set of
initializations of the class that would be performed by a user-written default
constructor for that class with no ctor-initializer (12.6.2) and an empty
compound-statement.
12.6/4 If a given non-static data member or base class is not named by ... in
initialiser list ... the entity is not initialized.
however, remember effective C++, if you declare a dtor then you should also declare a copy ctor, ctor and self-assignment (even if you declare as private)
Don't work around it, attack it directly.
You'll need a C++ parser. Using the parser you'll have to track the types of variables which have no been properly assigned within each constructor of the classes. Once you've got that going it's simply a matter of inserting the proper syntax to make initialization happen in a desirable way. It's not a simple script to write but it'll save you loads of headache later.
FIrst step is just getting output from the parse tree to label problems for you:
class Foo{
public:
Foo(int a) : mA(a){}
private:
int mA, mB;
};
you'll want your script producing messages like: In class Foo :: missing initializer mB
Then get brave and transform that output into an instruction set to traverse the parse tree and insert missing items so that your code looks like:
class Foo{
public:
Foo(int a) : mA(a), mB(0){}
private:
int mA, mB;
};
So my best advice is to not try to work around the issue, attack it directly. If you still have problems after that, grab your nearest static code analyzer and memory analyzer. Those are the tools that will help you best of all.
Are you sure you (the people purportedly citing the ISO C++ Standard) are actually citing it? And not being confused with the text for updated versions specified in TR's which are not actually Standards? Or C++11 which probably will be soon, but one can hardly expect MS to conform to something not yet officially a Standard.
I've started to pick up this pattern:
template<typename T>
struct DefaultInitialize
{
DefaultInitialize():m_value(T()){}
// ... conversions, assignments, etc ....
};
So that when I have classes with primitive members, I can set them to be initialized to 0 on construction:
struct Class
{
...
DefaultInitialize<double> m_double;
...
};
The reason I do this is to avoid having to remember to initialize the member in each constructor (if there are multiple constructors). I'm trying to figure out if:
This is a valid pattern?
I am using the right terminology?
This is a valid pattern?
It's a known "valid" pattern, i would say. Boost has a class template called value_initialized that does exactly that, too.
I am using the right terminology?
Well, your template can be optimized to have fewer requirements on the type parameter. As of now, your type T requires a copy constructor, unfortunately. Let's change the initializer to the following
DefaultInitialize():m_value(){}
Then, technically this kind of initialization is called value initialization, starting with C++03. It's a little bit weird, since no kind of value is provided in the first place. Well, this kind of initialization looks like default initialization, but is intended to fill things with zero, but respecting any user defined constructor and executing that instead.
To summarize, what you did was to value initialize an object having type T, then to copy that object to m_value. What my version of above does it to value initialize the member directly.
Seems like a lot of work to avoid having to type m_double(0). I think it's harder to understand at first glance, but it does seem fine as long as everything is implemented properly.
But is it worth it? Do you really want to have to #include "DefaultInitialize.h" everywhere?
To clarify, basically, you're:
Making your compile times longer because of the includes.
Your code base larger because you have to manage the deceptively simple DefaultInitialize class
Increase the time it takes other people to read your code. If you have a member of a class that's a double, that's natural to me, but when I see DefaultInitialize, I have to learn what that is and why it was created
All that because you don't like to type out a constructor. I understand that it seems very nice to not have to do this, but most worth-while classes I've ever written tend to need to have a constructor written anyway.
This is certainly only my opinion, but I think most other people will agree with it. That is: it would be handy to not have to explicitly initialize members to 0, but the alternative (your class) isn't worth it.
Not to mention that in C++0x, you can do this;
class Foo
{
private:
int i = 0; // will be initialized to 0
}
Some compilers don't properly implement value initialization. For example, see Microsoft Connect, Value-initialization in new-expression, reported by Pavel Kuznetsov.
Fernando Cacciola's boost::value_initialized (mentioned already here by litb) offers a workaround to such compiler bugs.
If you're just initializing basic types to zero, you can override new and have it memset allocated memory to zero. May be simpler. There are pros and cons to doing this.