Pointer initialization in class initialization - c++

Given
class Foo {
public:
bool *b;
Foo();
};
Foo::Foo()
:b()
{
}
int main()
{
Foo foo;
}
What does the b() do in the class initializer list? It seems to maybe initialize the pointer's value to 0.

This is value initialization; as the effect, built-in types will be zero-initialized. That means b will be initialized to 0 (the null pointer).
4) otherwise, the object is zero-initialized.
and
If T is a scalar type, the object's initial value is the integral constant zero explicitly converted to T.
and also
Zero- and value-initialization also initialize pointers to their null values.

Related

Is pointer type a literal type?

A scalar type is defined as
Trait class that identifies whether T is a scalar type. A scalar type
is a type that has built-in functionality for the addition operator
without overloads (arithmetic, pointer, member pointer, enum and
std::nullptr_t).
It inherits from integral_constant as being either true_type or
false_type, depending on whether T is a scalar type, no matter its
const and/or volative qualification.
It means pointer is scalar type.
Now if we go to definition of literal type:
A type is a literal type if it is:
a scalar type; or
a reference type; or
an array of literal type; or
-a class type (Clause 9) that has all of the following properties:
it has a trivial destructor,
every constructor call and full-expression in the brace-or-equal-initializers for non-static data members (if any) is a constant expression (5.19),
it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and
all of its non-static data members and base classes are of literal types.
Now, combining above 2 statements, it means pointer is literal type. However pointer can not be constexpr. can someone please clarify?
further see following code:
int a = 7;
constexpr int *pointer1 = &a;
int main ()
{
int b = 4;
constexpr int *pointer2 = &b;
}
pointer1 is fine but pointer 2 gives error. does that mean pointer to global is fine but to automatic variable is not? Does standard mention this anywhere ?
Pointers are literal types. They can be constexpr under certain conditions:
[expr.const] 6
... [a pointer is constexpr if] it contains the address of an object with static storage duration, the address past the end of such an object (5.7), the address of a function, or a null pointer value.
(Where "object with static storage duration" means a global or static object, or a subobject of such object.)
A demo:
int x;
int main()
{
constexpr int *ptr = &x; // Compiles.
// Doesn't compile: `error: '& foo' is not a constant expression`
// int foo;
// constexpr int *bar = &foo;
}
Apparently GCC (with -pedantic-errors -std=c++11/14/17) happily accepts out-of-range constexpr pointer arithmetic: constexpr int *ptr = &x - 10;, which seems like a bug to me.
Yes they are literals; yes they can be constexpr. To demonstrate:
constexpr int* foo=0;
int x = 7;
constexpr int* ptr=&x;
int main(){}

Template function that returns default constructed value

I have a function that returns default constructed value of template type:
template<typename T>
T do_stuff()
{
return T();
}
I use it like this:
int main(int argc, char** argv)
{
std::string str("hello");
int a = 10;
int *p = &a;
str = do_stuff<std::string>();
a = do_stuff<int>();
p = do_stuff<int*>();
return 0;
}
After I use it I have: str is an empty string, a eqauls 0 and p is a null pointer.
I can understand why std::string variable becomes an empty string (it has default constructor that constructs an empty string).
But why an int variable becomes 0 and a pointer becomes a null pointer.
Is it default template behaviour?
I use gcc 4.6.6 under Linux Centos.
From this reference on value initialization:
If T is a class type with at least one user-provided constructor of any kind, the default constructor is called.
If T is an non-union class type without any user-provided constructors, then the object is zero-initialized and then the implicitly-declared default constructor is called (unless it's trivial)
If T is an array type, each element of the array is value-initialized
Otherwise, the object is zero-initialized.
What is happening is that the last point in the above list.
The key is in
//------vv
return T();
For example, you can test the following, which is equivalent:
int x = int();
std::cout << x;
x will always be 0 in this case. The same is applied for the pointer - it's zero-initialized, "making" it NULL.
This is value initialization, "caused" by the parenthesis.
Because T() is value initialization, which for int and pointer types (and other basic types) is zero-initialization.
Just like to value initialize an int you'd do:
int x{};
int x = int();
//not initialized:
int x; //if not at namespace scope
int x(); //method declaration
This is as defined in c++ 11 standard, section 8.5:
To value-initialize an object of type T means:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized
And:
To default-initialize an object of type T means:
— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is
ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, the object is zero-initialized.
And:
To zero-initialize an object of type T means:
— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
— if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
— if T is a union type, the object’s first named data member 89) is zero-initialized;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
That is correct behaviour for the respective types, everywhere.
Primitive types are initialized differently depending on whether you explicitly request the default value (value initialization) or don't mention the initialization (default initialization).
If you construct primitive type without mentioning initialization (this is called default initialization), the value is random:
int x;
struct Y {
int x;
} x;
int *x = new int;
are all default initializations and will contain random value.
But if you mention the initializer, it becomes value initialization and the value is initialized to appropriate "zero" (0 for numbers, 0/nullptr for pointers):
int x = 0;
int x = int();
struct Y {
int x;
Y() : x() {} // the x() is important
} y;
struct Z {
int x;
} z = {};
int *x = new int();
are all value initializations and C++11 adds the following forms
int x{};
struct Y {
int x;
Y() : x{} {}
} y;
struct Z {
int x;
} z{};
int *x = new int{};
Beware of
int x(); // function, NOT A VARIABLE
it declares a function taking no arguments and returning int. This is called the "most vexing parse".
The T() is value initialization.
Use:
int x{};
int x = int();

Initializing member variables of a struct in c++

I have a struct with a few double values:
struct A {
double a;
double b;
}
if I create a new struct, e.g. A a, are all the members (e.g. a.a) initialized to zeroes automatically in C++?
Not by default (unless it's a variable of static storage - that is, a static or global variable).
There are a few ways to initialize a struct of this kind to "zeros":
A a = { 0.0, 0.0 };
A a = { };
A a = A();
or if you have a C++11 compatible compiler:
A a{0.0, 0.0};
A a{}
or add a constructor to the struct definition:
struct A {
double a;
double b;
A() : a(0.0), b(0.0) {}
};
8.5. Initializers [dcl.init] / 11.
If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an
object with automatic or dynamic storage duration has indeterminate value. [ Note: Objects with static or
thread storage duration are zero-initialized, see 3.6.2. — end note ]
and (ordering reversed for readability):
8.5. Initializers [dcl.init] / 6.
To default-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the
initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, no initialization is performed. [emphasis mine]
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type
with a user-provided default constructor.
They are default initialized. For builtin types like int or double, their value depends on where the struct is declared (as a rule of thumb (but just as that): Assume they are always garbage unless initialized).
In global scope or/and with static storage, they are all zeroes (incl. when the struct is a member of a struct which is at global scope).
At function-local scope, they are full of garbage.
Example:
#include <iostream>
struct Foo {
int x;
int y;
};
Foo foo;
int main () {
Foo bar;
std::cout << foo.x << ":" << foo.y << '\n';
std::cout << bar.x << ":" << bar.y << '\n';
}
This on the first run gives me
0:0
-1077978680:12574708
On the second run, without recompilation, this gives me:
0:0
-1075556168:12574708
A POD-struct can be initialized all zeroes using e.g. memset or just ...
Foo foo = {0}; // C and C++03
Foo foo{0}; // C++11
No. In the general case, they have unspecified values.
If you don't like this behaviour, you can provide a constructor:
struct A {
double a;
double b;
A(): a(0.0), b(0.0) {}
}

Default value of a function pointer in C++

What is the default value of a function pointer in C++? (Apparently it can't be NULL, so what is it?)
How is this program supposed to behave and why?
struct S { void (*f)(); };
int main()
{
S s = S();
s.f(); // What is the value of s.f?
}
First any pointer can be null. It is the one universal truth about pointers. That said, yours will be null, but not necessarily for the reasons you may think;
C++11 § 8.5,p10
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
This is important because your declaration includes this :
S s = S();
By the definition of value initialization:
C++11 § 8.5,p7
To value-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is called.
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized.
Which brings us to what it means for your object-type to be zero-initialized:
C++11 § 8.5,p5
To zero-initialize an object or reference of type T means:
if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T (103)
if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;
if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero- initialized and padding is initialized to zero bits;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
103) As specified in 4.10, converting an integral constant expression whose value is 0 to a pointer type results in a null pointer value.
The latter is the reason you're pointer is null. It will not be guaranteed-so by the standard given the same code, but changing the declaration of s to this:
S s;
Given a declaration like the above, a different path is taken through the standard:
C++11 § 8.5,p11
If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value. [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2.
Which then begs the last question, what is default initialization:
C++11 § 8.5,p6
To default-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is an array type, each element is default-initialized;
otherwise, no initialization is performed.
In your case the object s is zero-initialized which means the function pointer is NULL.
struct S { void (*f)(); };
int main()
{
S s = S();
if ( s.f == NULL)
std::cout << "s.f is NULL" << std::endl;
}
Output:
s.f is NULL
Online demo.
A function pointer can be NULL and you may assign NULL to it. Have a look here for instance:
#include <iostream>
using namespace std;
struct S { void (*f)(); };
int main()
{
S s = S();
s.f = NULL;
return 0;
}
I believe the way you call the constructor of the structure(with ()), f will be NULL.
Function pointer can be NULL, this way you can indicate that they don't point to anything!
In C++ (and C), pointers (regardless of type) do not have a default value per se; they take what ever happens to be in memory at the time. However, they do have a default initialised value of NULL.
Default Initialisation
When you don't explicitly define a constructor, C++ will call the default initialiser on each member variable, which will initialise pointers to 0. However, if you define a constructor, but do not set the value for a pointer, it does not have a default value. The behaviour is the same for integers, floats and doubles.
Aside
int main()
{
S s = S();
s.f(); // <-- This is calling `f`, not getting the pointer value.
}

How can i use member initialization list to initialize an array?

class A {
public:
A();
private:
char a[5];
int* ptr;
};
A::A() : a(0), ptr(0) { }
Is this right?
The only sensible thing you can do with a C-array in C++03 is value-initialize it (in C++11 and beyond it can be list-initialized).
From the C++03 standard, §8.5/7:
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
And from §8.5/5:
To value-initialize an object of type T means:
if T is a class type with a user-declared constructor, then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
if T is an array type, then each element is value-initialized;
otherwise, the object is zero-initialized
To zero-initialize an object of type T means:
if T is a scalar type, the object is set to the value of 0 (zero) converted to T;
if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
if T is a union type, the object’s first named data member) is zero-initialized;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
So, if your constructor definition is changed to
A::A() : a(), ptr() { }
then you are guaranteed that post-construction, all 5 elements of A::a will have the value '\0' and A::ptr will be null.
Afraid not; C++ doesn't support initialising arrays like this.
You'll just have to assign to its members in A's constructor body, or you can use value-initialisation if you don't really care what the values are:
struct A {
int x[5];
A() : x();
};
C++0x does let you give all the values, though:
struct A {
int x[5];
A() : x{1,2,3,4,5} {}
};
Note, though, that because arrays are not class-objects, you won't be able to do this:
struct A {
int x[5];
A(std::initializer_list<int[5]>& i) // or whatever the T should be
: x{i} // or x(i)
{}
}
A a({1,2,3,4,5)};