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.
Related
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.
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.
It recently occurred to me that more often than I'd like to admit, the fix for a "strange bug that only materializes occasionally" is to simply initialize the one member variable of a class I forgot to add to the initializer list.
To prevent wasting time on such bugs in the future, I've been toying with the idea to completely abandon built-in primitive types and replacing them with wrapper classes that act exactly like their primitive counterparts, except that they'll always be initialized.
I'm proficient enough in C++ to know that I can write classes that get very close to that goal. I.e. I'm confident I can write a MyInt class that behaves very much like a real int. But I also know C++ well enough to know that there's probably an arcane thing or two I'd be missing ;)
Has anyone done something like this before? Any pointers to relevant documentation, or list of pitfalls to watch out for? Is this even a good idea, or are there any downsides I'm not seeing?
Thanks!
EDIT: Thanks everyone for your comments, here's an update. I started playing with Jarod42's wrapper snippet and see if I could convert a small hobby project codebase. Not completely unexpectedly, it's quite a PITA, but would probably be doable. It does start feeling like a very big hammer for this problem though.
Compiler warnings are not a real option, since only a single one (-Weffc++) seems to find the problem and it only exists for gcc, i.e. this is not a safe, portable solution.
My conclusion so far is to start using C++11's in-class initialization for all primitive members as suggested by Praetorian below. I.e. something like
struct C {
int x = 0; // yay C++11!
};
.. and hope that after some time, ommitting such initialized feels as "naked" as declaring an unititialized variable in code within a function (which I've stopped doing a long time ago). This seems much less error-prone than trying to keep the initializer list(s) up-to-date, because it's right there with the declaration.
C++11 makes it quite easy to avoid this pitfall by allowing in-class initialization of non-static data members. For example:
struct foo
{
foo(int i) : i(i) {} // here i will be set to argument value
foo() {} // here i will be zero
int i = {}; // value (zero) initialize i
};
This feature is not restricted to trivial types either. So just start initializing data members as soon you declare them within the class definition.
If your compiler doesn't support this feature, try cranking the warning level up to see if it'll tell you about uninitialized data members. For instance, g++ has the -Weffc++ flag that will warn you about uninitialized data members (amongst other things).
Next thing to try would be a static analysis tool to catch these mistakes.
In conclusion, there are several things I'd try before going down the path of boxing every trivial data type.
It's a lot easier to just turn on compiler warnings. Most decent compilers will warn you about using uninitialized variables - granted there are a few edge cases that compilers can miss.
Try better debugging.
You can switch on compiler warnings for uninitialized variables (see this SO question).
You can also use programs that do this and other checking of your code (static analysis), like cppcheck, which lists uninitialised variables.
Also try changing how you code. In C++ you have control over when memory is allocated, what constructors are used, and so on. If you are coding in a style where you construct objects with partial data, and then later populate other pieces, then you are likely to run into uninitialised variables a lot. But if you make sure that all the constructors construct a valid object in a valid state, and avoid having multiple points of truth (see Single Point Of Truth principle), then your errors are more likely to be caught by the compiler - you would have to pass an uninitialised variable as a value (which VC++ will warn you on), or have the wrong number or type of things in your constructor call (compile error), etc.
Might I suggest you pick out your most recent source of this kind of thing, complete with the chain of structures that got you there, and ask how you might restructure it better? There is a particularly disciplined style of coding in C++ which makes maximum use of the compiler and thus tips you off as early as possible. Really the bugs you create when using that style shouldn't be anything less than multi-threading issues, resource issues etc.
I worry that if you initialise everything just to prevent such errors, you'll miss out on learning that disciplined style which extends so much further than uninitialised variables.
Following may help:
template <typename T>
class My
{
public:
constexpr My() : t() {}
constexpr My(const T&t) : t(t) {}
operator T& () { return t; }
constexpr operator const T& () const { return t; }
const T* operator& () const { return &t; }
T* operator& () { return &t; }
private:
T t;
};
Note sure if it is better to check that My<int> is used in place of each possible uninitialized int...
But note that you have to do special job for union anyway.
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.