Explicit initialization of struct/class members - c++

struct some_struct{
int a;
};
some_struct n = {};
n.a will be 0 after this;
I know this braces form of initialization is inherited from C and is supported for compatibility with C programs, but this only compiles with C++, not with the C compiler. I'm using Visual C++ 2005.
In C this type of initialization
struct some_struct n = {0};
is correct and will zero-initialize all members of a structure.
Is the empty pair of braces form of initialization standard? I first saw this form of initialization in a WinAPI tutorial from msdn.

The empty braces form of initialization is standard in C++ (it's permitted explicitly by the grammar). See C Static Array Initialization - how verbose do I need to be? for more details if you're interested.
I assume that it was added to C++ because it might not be appropriate for a 0 value to be used for a default init value in all situations.

It is standard in C++, it isn't in C.
The syntax was introduced to C++, because some objects can't be initialized with 0, and there would be no generic way to perform value-initialization of arrays.

The {0} is C99 apparently.
Another way to initialize in a C89 and C++ compliant way is this "trick":
struct some_struct{
int a;
};
static some_struct zstruct;
some_struct n = zstruct;
This uses the fact that static variables are pre-initialized with 0'ed memory, contrary to declarations on the stack or heap.

I find the following link to be very informative on this particular issue
http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/strin.htm

Related

Iterable Designated Initializer Alternative in C++

In C99, a struct array can be initialized
static struct {char* tag; char* msg;} help_info[] = {[0]={"tag0","msg0"}, [1]={"tag1", "msg1"}};
This is not valid in C++. What is a possible alternative to replicate this behavior for an iterable object containing defined information?
C++20 added designated initializers to C++. There are some restrictions compared to C, in a couple of different directions. In your case, the main difference of note is that C++ has tightened up a bit of the type system so you can no longer initialize a char * from a string literal.
In C, you can initialize a char * from a string literal for the sake of backward compatibility, but you still have to treat it as if it were a char const *--that is, if you try to write to the string literal you get undefined behavior (and on a modern machine, you'll typically get something on the order of a seg fault that will kill your program).
C++ now demands that you recognize that limitation by using char const * explicitly. If we change your code to suit:
static struct {char const* tag; char const* msg;} help_info[] =
{[0]={"tag0","msg0"}, [1]={"tag1", "msg1"}};
...and compile it as C++, it's perfectly fine.
Do note there are other limitations that don't exist in C (but they don't affect this code). For example, C++ demands that the initializers be in order, so in C you also do this:
static struct {char const* tag; char const* msg;} help_info[] =
{[1]={"tag1", "msg1"}, [0]={"tag0","msg0"}};
...so the initializer for [1] precedes the initializer for [0], but in C++ that's forbidden.
As stated in another answer:
From this link designated-initializer not supported in C++ Designated Initializers:
Note: out-of-order designated initialization, nested designated initialization, mixing of designated initializers and regular initializers, and designated initialization of arrays are all supported in the C programming language, but are not allowed in C++.
However, I believe this code will meet your need.
static struct { const char* tag; const char* msg; } help_info[] = { {"tag0","msg0"}, {"tag1", "msg1"} };
From this link designated-initializer not supported in C++ :
Note: out-of-order designated initialization, nested designated
initialization, mixing of designated initializers and regular
initializers, and designated initialization of arrays are all
supported in the C programming language, but are not allowed in C++.
I think, it is not possible.

If the `std::array` does not have a constructor that takes `std::initializer_list` how does the initialization then work? [duplicate]

The section "Array Initialization" in Chapter 4, page 231 of "Thinking in Java, 2nd Edition" has this to say:
Initializing arrays in C is error-prone and tedious. C++ uses
aggregate initialization to make it much safer. Java has no
“aggregates” like C++, since everything is an object in Java. It does
have arrays, and these are supported with array initialization.
Why is it error prone and tedious in C? What does it mean by aggregate initialization and why is it safer? I came across the chapter "Aggregate initialization" in Bruce Eckel's "Thinking in C++" (2nd Ed.), but it doesn't convince me of anything.
First of all, to answer the main question, aggregate initialization means the use of brace-enclosed initializer lists to initialize all members of an aggregate (i.e. an array or struct [in C++, only certain types of structs count as aggregates]).
Obviously,
int ar[] = { 1 , 2 };
is safer than
int ar[2];
ar[0] = 1;
ar[1] = 2;
because the latter gives ample opportunity for typos and other errors in the indices of the individual elements to be initialized.
Looking at today's C and C++, it's unclear to me why the author makes a distinction between C and C++. Both languages enable aggregate initialization for arrays.
One possibility is that the author referred to old versions of the C Standard. Notably, in ANSI C (C89) an important restriction applied to the use of aggregate initialization: All initializers had to be constant expressions:
/* This is possible in C89: */
f(int i)
{ int ar[] = { 1 , 2 }; }
/* But this is not
(because i is not a constant expression):
*/
f(int i)
{ int ar[] = { i , i+1 }; }
This is due to 3.5.7 in C89 (quoting from the draft I found here):
All the expressions in an initializer for an object that has static storage duration or in an initializer list for an object that has aggregate or union type shall be constant expressions.
This clearly limits the usefulness of aggregate initialization (and even in 1989, I believe many compilers implemented extensions to enable aggregate initialization also for non-constant expressions).
Later versions of the C Standard did not have this restriction, and the standardized versions of C++ (starting with C++98), I believe, never had any such restriction.
I can only speculate, but perhaps this is what the author had in mind?
I am assuming that the author is warning you about the lack of enforcing size constraints in C and C++. In C and C++, arrays decay down to pointers to their first element. It then uses pointer arithmetic to find the element you are refering to by index. Since arrays are not objects and the compiler makes no effort to store their size, there are no length checks. In java, arrays are objects and therefore their size is known. This size can be checked against, which safe guards the developer from accessing memory which doesn't belong to him/her when overstepping the bounds of the array.
I find it strange the statement 'C++ uses aggregate initialize to make it much safer' was even used in this context.
Aggregate initialization, which is common to most modern languages, is as follows
int intArray[3] = {1,2,3};
int int2DArray[2][2] = {{1,2}, {3,4}};
This type of initialization assumes you know the size of the array beforehand and its contents. This type of initialization safe guards one from over stepping the boundary and provides for initializing an array with set values. Maybe in this case the author has in a mind a developer who declared a static C array of size 5. This developer then creates a loop to initialize its content but oversteps the boundary of the array by one, writing to memory that is not his/hers.

C++11 Variable Initialization and Declaration

With C++11 came a new way to initialize and declare variables.
Original
int c_derived = 0;
C++11
int modern{0};
What are the pros and cons of each method, if there are any? Why implement a new method? Does the compiler do anything different?
You're mistaken -- the int modern(0) form (with round brackets) was available in older versions of C++, and continues to be available in C++11.
In C++11, the new form uses curly brackets to provide uniform initialisation, so you say
int modern{0};
The main advantage of this new form is that it can be consistently used everywhere. It makes it clear that you're initialising a new object, rather than calling a function or, worse, declaring one.
It also provides syntactical consistency with C-style ("aggregate") struct initialisation, of the form
struct A
{
int a; int b;
};
A a = { 1, 2 };
There are also more strict rules with regard to narrowing conversions of numeric types when the curly-bracket form is used.
Using braces was just an attempt to introduce universal initialization in C++11.
Now you can use braces to initialize arrays,variables,strings,vectors.

what is aggregate initialization

The section "Array Initialization" in Chapter 4, page 231 of "Thinking in Java, 2nd Edition" has this to say:
Initializing arrays in C is error-prone and tedious. C++ uses
aggregate initialization to make it much safer. Java has no
“aggregates” like C++, since everything is an object in Java. It does
have arrays, and these are supported with array initialization.
Why is it error prone and tedious in C? What does it mean by aggregate initialization and why is it safer? I came across the chapter "Aggregate initialization" in Bruce Eckel's "Thinking in C++" (2nd Ed.), but it doesn't convince me of anything.
First of all, to answer the main question, aggregate initialization means the use of brace-enclosed initializer lists to initialize all members of an aggregate (i.e. an array or struct [in C++, only certain types of structs count as aggregates]).
Obviously,
int ar[] = { 1 , 2 };
is safer than
int ar[2];
ar[0] = 1;
ar[1] = 2;
because the latter gives ample opportunity for typos and other errors in the indices of the individual elements to be initialized.
Looking at today's C and C++, it's unclear to me why the author makes a distinction between C and C++. Both languages enable aggregate initialization for arrays.
One possibility is that the author referred to old versions of the C Standard. Notably, in ANSI C (C89) an important restriction applied to the use of aggregate initialization: All initializers had to be constant expressions:
/* This is possible in C89: */
f(int i)
{ int ar[] = { 1 , 2 }; }
/* But this is not
(because i is not a constant expression):
*/
f(int i)
{ int ar[] = { i , i+1 }; }
This is due to 3.5.7 in C89 (quoting from the draft I found here):
All the expressions in an initializer for an object that has static storage duration or in an initializer list for an object that has aggregate or union type shall be constant expressions.
This clearly limits the usefulness of aggregate initialization (and even in 1989, I believe many compilers implemented extensions to enable aggregate initialization also for non-constant expressions).
Later versions of the C Standard did not have this restriction, and the standardized versions of C++ (starting with C++98), I believe, never had any such restriction.
I can only speculate, but perhaps this is what the author had in mind?
I am assuming that the author is warning you about the lack of enforcing size constraints in C and C++. In C and C++, arrays decay down to pointers to their first element. It then uses pointer arithmetic to find the element you are refering to by index. Since arrays are not objects and the compiler makes no effort to store their size, there are no length checks. In java, arrays are objects and therefore their size is known. This size can be checked against, which safe guards the developer from accessing memory which doesn't belong to him/her when overstepping the bounds of the array.
I find it strange the statement 'C++ uses aggregate initialize to make it much safer' was even used in this context.
Aggregate initialization, which is common to most modern languages, is as follows
int intArray[3] = {1,2,3};
int int2DArray[2][2] = {{1,2}, {3,4}};
This type of initialization assumes you know the size of the array beforehand and its contents. This type of initialization safe guards one from over stepping the boundary and provides for initializing an array with set values. Maybe in this case the author has in a mind a developer who declared a static C array of size 5. This developer then creates a loop to initialize its content but oversteps the boundary of the array by one, writing to memory that is not his/hers.

Designated Initializers in C99: How to handle empty uninitialized struct members in C11?

Since in C I can call the members of a struct by name (myStruct.myMember = ) I was wondering what I would do in C++ with those members that are not initialized.
So as I understood, C++ does not support this kind of initialization:
static struct usb_endpoint_descriptor fs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16 (64),
};
But when I use correct syntax, how do I handle members that are not initialized?
Let's say I want bDescriptorType uninitialized. Do I set it to NULL?
static struct usb_endpoint_descriptor fs_source_desc = {
USB_DT_ENDPOINT_SIZE,
NULL,
USB_ENDPOINT_XFER_BULK,
__constant_cpu_to_le16 (64)
};
Or is there any way in C++ to initialize the structure's members by their name?
how do I handle members that are not initialized?
The feature you describe is called designated initializers and was introduced in C99. It is not supported by C++. All members that are not initialized explicitly are guaranteed to be set to zero (*).
Maybe you didn't consider it, but the same applies to regular struct initialization as well. Example:
typedef struct
{
int a;
int b;
} ab;
ab mystruct = { .a = 1 }; // a is 1, b is guaranteed to be 0
ab mystruct = { 1 }; // a is 1, b is guaranteed to be 0
(The last example is also true for C++.)
This language rule is the reason why we can initialize all elements in a struct/array to zero by typing:
ab mystruct = { 0 };
because it actually means "set a to zero, and let then all other elements be implicitly initialized to zero".
(*) Formally, they are initialized as if they had static storage duration, i.e. data gets set to zero, pointers get set to NULL etc. C11 6.7.9/10.
If you use C++, then use constructors. Init by NULL is more C-way really.
And no, there is no standard C++ way to use named parameters (something like boost::parameters may help, but there is no need to it here).
Your case may be something like
struct usb_endpoint_descriptor
{
usb_endpoint_desctiptor(type bL, type bAttr, type wSize) :
bLength(bL), bAttributes(bAttr), wMaxPacketSize(wSize) {}
type bLength;
type bDescriptorType;
type bmAttributes;
type wMaxPacketSize;
};
However, it's bad style to leave variables not-initialized in C++.
So, if you use C structure, you can
1) Write C++ wrapper.
2) Write derived class.
3) Initialize field, that you don't want to initialize with some default value.
FYI, All of the previous answers were correct. there was no support for designated initializers in C++... until C++20.
C++20 added aggregate initializers in that version of the C++ standard.
The syntax is different than C99 dot notation because, I guess the standard committee wanted the syntax to be more idiomatically Cplusplussesque.
Here is an on point stack overflow question
Designated initializers in C++20
And here is a popular reference site. https://en.cppreference.com/w/cpp/language/aggregate_initialization