I have a struct with many members and with different types (it's like 20 members):
enum TheEnum
{
FIRST = 0,
SECOND,
...
}
struct TheStruct
{
TheEnum z; // <--- the point !!! note that this is the first member (edited)
int a;
int b;
char c[32];
...
}
Due to there is an enum type member, I cant just declare like:
TheStruct Object = {0};
It will give compile error, but this initialization is the best way in my opinion.
The other ways that I can think of is:
1. ZeroMemory it, but I dont like this one.
2. Write a constructor, but this needs a lot of work.
3. Just don't initialize it.
So, is there any way to solve the enum problem? Should I pick a way in these 3?
Thanks!
EDIT:
My big mistake, the error only occurs when TheEnum presents as the first member.
Compiled using vs2008 and as C++ code.
The error is C2440. http://msdn.microsoft.com/en-us/library/sy5tsf8z%28v=VS.80%29.aspx
[edit] as the question changed
If you initialize a struct, you have to provide the correct types in your initializer.
In your case, the correct initialization would look like this:
TheStruct Object = {FIRST};
Your initialization list initializes the given number of struct members with what you have written and the rest of the struct with '0'.
Since your first member is an enum, you have to initialize that enum in this case.
[/edit]
there is nothing necessary. if you're compiling in C and not C++ just don't forget to write enum and struct and everything should work...
enum TheEnum
{
FIRST = 0,
SECOND,
...
}
struct TheStruct
{
int a;
int b;
char c[32];
...
enum TheEnum z; // <--- the point !!!
}
struct TheStruct Object = {0};
You can initialize the enum member just like any other. For example: TheStruct temp = {0,0,"", FIRST};
Related
Trying to create empty constructor for a struct that has union as a member variable. Union also has a struct and an additional variable as member variables.
Took few approaches, but non were successful. How can I create an empty constructor for nested anonymous structures? How can I call the member variables afterwards?
typedef struct test_struct
{
int a;
union {
int b;
struct {
int c;
};
};
} test_struct;
Below won't compile
test_struct() : a(10), b(20), c(30) {
}
Below sets both b and c as 30
test_struct() : a(10), b(20) {
c = 30;
}
Here is the print function
int main(void)
{
test_struct *ts = new test_struct();
printf("%i\n%i\n%i\n", ts->a, ts->b, ts->c);
return 0;
}
I trying to create an empty constructor that will print 10 20 30 with my printf().
EDIT: I received comments on how I cannot initialize union in this way. However, the header file I received (which I cannot change at all) has structs defined in such nested structure. I do not know how the initialization goes in the back, but my code has to print out values for all the member variables. (a, b, and c for the below example code). Any approaches/reading I can do to achieve this?
Apart from the erroneous way you use union, let's stick to the question about your nested struct. The answer is simple: you can't specify constructors for nested structs. So, even if you fix the code and use correctly your nested struct, you won't be able to declare a constructor or destructor for that anonymous class/struct because the constructor and destructor names need to match the class name.
In the example you posted, the anonymous class is local. It means that it has no linkage so mangled name is not even created.
So far I've read about structs, with and without pointers. My question is about a struct in combination with a class and main. What I learn from K&R and c++ sites is that a struct can't contain values. The values I want to assign to the members will be constants. In several posts I read that I should put the struct inside the class and even inside private. The setup I use was:
class C
{
struct something {const float m = 3} s;` //actually 12 members. Compiler doesn't accept values: "ISO C++ forbids initialization of member"
function foo(struct something s){ float m = s.m; <..do something..>}` //struct s actually used in several functions
};
int main(){C c;}
Then I created 2 structs, and letting the 2nd assign values to the members of the first, which I find ugly. But why did that get accepted by gcc? So how can I assign the values only once in a proper way since assigning values has to be done inside a function. BTW, I'm using Ubuntu gcc-4.6.1.
Thank you for an answer.
struct something {const float m = 3} s;` //actually 12 members. Compiler doesn't accept values: "ISO C++ forbids initialization of member"
to fix above do
struct something {
something (float const& f = 3) : m(f)
const float m;
} s;
The difference between struct and class in C++ is that structs default their members to public while classes default to private (same goes for inheritance). That's all there is to it.
Then, in C++03 const float m = 3; is not valid as a member declaration. You would need to declare a constructor for your struct:
struct something
{
const float m;
const float n;
something() : m(3), n(42) {}
} s;
Structs AND classes in C++ suffer from this problem. You can only declare a value in a class definition if the variable is static and shared among all the instances of the class. If your variable is const I think that may be a good choice.
A good solution for non-const variables is a simple one - assign the desired values to all the variables in the default constructor of your class or struct.
e.g
struct Something
{
float value;
Something():value(5.0f) {};
}
I have a structure that has 3 different types of values in it (char, float, int).......I need to set everything to 0 at the beginning of the program. How do I do that?
There are two usual ways:
A a = A();
or
A a = {};
The first has the advantage that if you later provide
constructor, it still works (as long as you provide a default
constructor).
With regards to the suggestion to use memset: memset is only
guaranteed to work for integral types. I can't imagine it not
working for a float, but formally, it's not guaranteed. And
of course, if you later modify the struct, it might stop
working. It is a solution to avoid.
struct A
{
int a;
char b;
float c;
};
struct A is an aggregate, built-in types initialized to 0. You can initialize to A in two ways:
//Class method pass to function
int main()
{
A a = {}; // initialize single A to 0
A b = A(); // same effort
A c[10] = {}; // initialize array to 0
return 0;
}
You could make use of a constructor to initialise all of your elements. So you will be able not just to use 0 maybe also other values.
struct A
{
int a;
char b;
float c;
A(int _a=0,char _b=0,float _c=0.0) : a(_a), b(_b), c(_c) {}
};
int main()
{
A a;
// work with a
return 0;
}
There are several ways:
Use initializer mystruct x = { '\0', 0.0f, 0 };
Use mystruct x; memset(&x, 0, sizeof(x));
Write a function (or, in C++, a constructor) that sets each value to zero.
Generally, first one is the most obvious, but if you have a large number of structs, then you may find either of option 2 or 3 more suitable.
Note: using memset is ONLY safe on data structures that ONLY contain data. In C++, a struct and a class are almost identical, and a struct that has member functions, has other struct or class members or has inherited from another class or struct, will definitely not be safe to use memset on. And of course, this is particularly dangerous if you start out with a plain data struct, and then ADD functionality into the struct that "breaks" the 'only data' promise.
Edit: Just to be clear, the struct doesn't do anything, as in it has no functions. I think I gave the impression that I thought using an initialiser list and leaving the body of the constructor empty was the issue at hand.
Say I'm using a struct to hold two values, and I have a constructor just so I can create an arbitrary struct like this:
struct twoValues
{
int x;
int y;
twoValues(int x_, int y_):y(y_),x(x_)
{}
};
someFunction(twoValues(1,2));
That saves me from having to do this:
twoValues anInstance;
anInstance.x=1;
anInstance.y=2;
someFunction(anInstance);
Edit: You're all correct, I could also initialise with the following:
twoValues anInstance = {1,2};
I see nothing wrong with this but I had some feedback from a C++ test and one of the negative feedback marks was "constructors for structs that don't do anything". I had limited contact with the guy testing me and so never asked why.
Is it a bad thing and why? I would rather carry on doing it.
It depends on what the struct is being used for. As others have said,
the constructor means that the class is no longer a POD, and that
aggregate initialization cannot be used for it. In particular, you
cannot have something at namespace scope like:
TwoValues const table[] =
{
{ 1, 2 },
{ 3, 4 },
// ...
};
You can have:
TwoValues const table[] =
{
TwoValues( 1, 2 ),
TwoValues( 3, 4 ),
// ...
};
but it is more verbose, and it implies dynamic initialization, which may
result in order of initialization issues.
On the other hand, without the constructor, you cannot create temporary
instances on the fly. Instead of:
extern void f( TwoValues const& );
// ...
f( TwoValues( 1, 2 ) );
you have to write:
extern void f( TwoValues const& );
// ...
TwoValues tmp = { 1, 2 };
f( tmp );
If the object is dynamically allocated, it's even worse, since you
either have to allocate first, then initialize, or create a temporary as
above, and then write new TwoValues( tmp ) and use the implicit copy
constructor.
You have to choose. Depending on what the struct is used for, one or
the other will be preferred; on one hand, I have a lot of structs which
are used exclusively in static tables, and intentionally don't have a
constructor (and contain only types which support static
initialization), and use them a lot for configuring code. On the other
hand, I also have a lot of structs which are internal to a class, along
the lines of Node in a tree or a graph; these almost always have a
constructor, to facilitate creating them on the fly. There's no
"correct" answer without knowing the role of the struct in your
application.
Declaring an empty constructor has side-effects..
Even though your constructor has an empty body it is still considered to be a constructor, and therefore certain object properties will be lost - such as the object being POD.
Some cases require the use of Plain Old Data-types, which can make it undesirable to do what you've done without a specific reason.
Read more about initialization without a defult constructor in the next section.
c++03 && c++11
You can initialize your members with values without explicitly defining a "constructor that doesn't do anything", just use the brace-initialization syntax as in the below snippet.
struct Obj {
int x, y;
};
Obj a = {1,3}; /* a.x = 1, a.y = 2 */
c++03
The downside of not having a constructor is that you cannot initialize the object using = { ... } in certain circumstances when writing C++03.
C++11 fixes this for you, see the next section for relevant examples.
c++11
In C++11 the initialization using braces ( = { ... }) has been given increased functionality.
As seen in the below snippet where the defined constructor of Obj is called even though we use the same form of initialization as earlier in this post.
struct DoubleBoth {
DoubleBoth (int x, int y)
: x(x*2), y(y*2)
{}
int x, y;
};
The snippets below were all illegal prior to C++11:
DoubleBoth a = {1,2}; /* a.x = 2, a.y = 4 */
struct Wrapper {
Wrapper ()
: value {3,4}
{}
DoubleBoth value;
};
void func (DoubleBoth v = {1,2}) { // c++11 only
...
}
func ({4,5}); // c++11 only, c++03 requires `DoubleBoth obj (0,1); func (obj);`
It's much safer to have this kind of constructor, than to initialize with a list.
When you initialize with a list :
twoValues anInstance = {1, 2};
It really depends on the order of the members in the struct. Which in most cases is totaly random to begin with.
If another programmer happens to add another member, or to sort the members by alphabet, it wont work correctly.
Having a constructor that assigns the values to the right member by NAME is much safer.
You've stopped twoValues from being a POD and have prevented instances of the struct from being default- or value- initialized which are often desirable properties. Personally, I would prefer to have a free function for making temporary instances if you need a simple C++03 friendly approach.
E.g.
twoValues makeTwoValues(int x_, int y_)
{
twoValues tmp = { x_, y_ };
return tmp;
}
void f() {
someFunction(makeTwoValues(1,2));
}
E.g. initializing a member of type twoValues
class X {
twoValues tv;
public:
X(int x, int y) : tv(makeTwoValues(x, y)) {}
};
Probably because you can initialize it like this:
twoValues anInstance = {1, 2};
However, without the constructor you cannot initialize a anInstance in another struct's initializer list in C++03. For example:
struct Bar {
twoValues v_;
Bar() : v_(1,2) {} // error!
Bar() { v_ = {1,2}; } // have to assign value in constructor body
Bar() : v_{1,2} {} // OK in C++11
};
so in fact the constructor does something, and it does serve a very useful purpose in C++03. It is less of an issue in C++11.
There is nothing wrong with this contructor.
Also, it does something, it affect values to x and y, which is what I would expect from such a constructor.
But, maybe there are some coding rules in your company that says that you should do it another way. In that case I would recommend you ask the person that gave you the feedback and make the necessary modifications.
The constructor makes the struct a non-POD which may not be desirable in some cases.
If your struct doesn't have constructor, then your struct will be POD1, and you will be allowed to initialize like this:
twoValues anInstance = {1,2}; //C++03 and C++11 both!
twoValues anInstance {1,2}; //C++11 only
which are good.
1. Actually there are other things which make a struct non-POD. So just because your struct doesn't have constructor doesn't necessarily mean it is POD. You would like to see this post to know what those other things are.
Structures can have constructors, and the syntax is the same as for classes in C++. The difference between a class and a struct is that class-members are private by default, while struct-members default to public, however Unions will not allow constructors in the structs. You can make a constructor on the union though.
I've found a strange looking piece of code in a project I have to maintain. There's an empty array member of a class which doesn't lead to an compiler error. I've tested some variations of such a code with MSVC 10.0:
template<class T> struct A {
int i[];
}; // warning C4200: nonstandard extension used : zero-sized array in struct/union
template<class T> struct B { static int i[]; };
template<class T> int B<T>::i[];
struct C {
int i[];
}; //warning C4200: nonstandard extension used : zero-sized array in struct/union
template<class T> struct D { static int i[]; };
template<class T> int D<T>::i[4];
template<> int D<int>::i[] = { 1 };
int main()
{
A<void> a;
B<void> b;
C c;
D<void> d0;
D<int> d1;
a.i[0] = 0; // warning C4739: reference to variable 'a' exceeds its storage space
b.i[0] = 0; // warning C4789: destination of memory copy is too small
c.i[0] = 0; // warning C4739: reference to variable 'c' exceeds its storage space
int i[]; // error C2133: 'i' : unknown size
d0.i[0] = 0; // ok
d0.i[1] = 0; // ok
return 0;
}
The error message at int i[] is absolutely sensible to me. The code which is shown with class D is well-formed standard C++. But what's about the classes A, B and C? What kind of types are the member variables int i[] in this classes?
EDIT:
your doubt is explained by the definition of the extension to the language, which allows for zero-sized arrays at the end of structs/unions. I have not tried it, but if you declare another member after the zero-sized array, it should fail.
so, if you allocate a variable on the stack, you have to know its size; the exception to the rule is when allocating an array at the end of a struct/union, where some C-typical trickery is possible.
In c++ this raises a warning because the default copy constructor and assignment operator will probably not work.
PREVIOUS ANSWER:
The compiler warns you about the fact that you are trying to define an array with zero size. This is not allowed in standard C/C++.
Let's see the differences class by class.
In class D:
template<class T> struct D { static int i[]; };
it works because you are just declaring the type of a static member variable. For this to link, you need also defining the actual array, in a definition statement like you do:
template<> int D<int>::i[] = { 1 };
here you also specify the size of the array through the initializer.
With class B, you are doing something similar, but the definition is:
template<class T> int B<T>::i[];
i.e., you don't specify the size and get the warning.
With class A, more of the same, you are defining a member variable of type array without the size.
Good one. Just to be certain, you are wondering why the compiler isn't flagging it as an error right? In that case, I think this problem is unpredictable across compilers but I'm aware of this happening on MSVC all the time.
http://support.microsoft.com/kb/98409
Let me see if I can explain it like they did. If I were to declare a struct with an empty array like this,
struct a
{
int x;
char empty[];
};
the compiler might allocate 4 bytes for x and probably another 4 bytes for the char pointer. empty will contain the address 4 bytes past the start of struct a.
Since it is a character array of no length, trying to access it would be an error since there is no trailing 0 to signify the end of the string.
I could choose to initialize the struct later to point to the start of an actual string to overcome this error.
struct a myStruct = { 1, "hello world"}; // empty now points to the start of "hello world"
Since a struct is basically a class, turns out you can do the same thing with a class if you make sure its an aggregate and not a full class.
So there ya go. MSVC compilers treat arrays with no fixed sized as a pointer when declared within a struct/class. Remember that class definitions are merely just declarations. The compiler doesn't allocate space for them until you create an instance for it. When you start to think about it, it sorta makes since. How will the compiler know if you plan to allocate storage for it later. It becomes a run-time artifact but the compiler was still smart enough to warn you about the problem.