Consider the code
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
struct B
{
public:
void f() { for (auto &v : member) { std::cout << v << std::endl; } }
private:
int member[100];
};
int main()
{
B b{};
b.f();
}
I think this code is guided by $8.5.4/3
List-initialization of an object or reference of type T is defined as follows:
— If the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
Instead the VS2013 compiler emits all 0xCCCCCCCC implying that it is leaving all elements of b.member as uninitialized. So, it appears it is performing default initialization instead of value initialization.
Please let me know if I am missing something.
What you want to say is this:
int main()
{
B b = {}; // = {} expresses that you want to zero-init the member vars
b.f();
}
If B has a (non-default) constructor or any members with constructors, the above code sample of using ={} may generate a compiler error.
Your code sample can be simplified even further.
#include <iostream>
struct B
{
public:
void f() { std::cout << member << std::endl; }
private:
int member;
};
int main()
{
B b{};
b.f();
}
This produces the output:
-858993460
which is 0xCCCCCCCC in hex, the debug pattern the VC compiler fills memory with in Debug builds. This seems to be a known bug with both VS2012 and VS2013 as reported here.
You can work around the error by defining a constructor that value initializes the data member individually. In your case adding this constructor will result in all elements of member being 0
B() : member{} {}
Related
C code
#include <stdio.h>
typedef struct
{
int a;
}A;
int main()
{
A(); // this line gives error
return 0;
}
Output
Error: Expected identifier or '('
C++ code
#include <iostream>
struct A
{
int a;
A()
{
std::cout<<"Ctor-A\n";
}
~A()
{
std::cout<<"Dctor-A\n";
}
};
int main()
{
A(); // creates temporary object and destroyed it
return 0;
}
Output
Ctor-A
Dctor-A
I know about the "Rule of three", but code becomes complicated and most compilers don't give errors if we don't follow the rule. So I avoided creation of a copy constructor and an overloaded assignment operator.
Why does A()/A{} create a temporary object in C++, but not in C? What's another way to create a temporary object in C?
In C (C99 and later) you can create a structure with automatic lifetime using a Compound Literal.
The syntax is (A){ initializers, for, struct, members }.
The lifetime is automatic, not temporary, so the structure created in this way does not vanish at the end of the full-expression, but at the end of the enclosing scope.
This expression
A()
is considered by C compilers as a function call. In C++ such an expression means a call of a constructor provided that A is a class type.
To create a temporary object in C you could declare a function like for example
struct A { int a; } A( int x )
{
struct A a = { .a = x };
return a;
}
and then you can call the function creating a temporary object of the type struct A like
A( 10 );
Here is a demonstrative program.
#include <stdio.h>
struct A { int a; } A( int x )
{
struct A a = { .a = x };
return a;
}
int main(void)
{
struct A a = A( 10 );
printf( "a.a = %d\n", a.a );
return 0;
}
The program output is
a.a = 10
A() calls the constructor for the struct A in the C++ code. However, C doesn't support constructors / destructors, or even objects (in the sense of OOP) in fact. The only way to create a temporary object as you describe in C would be to declare a variable of type A and wait for it to go out of scope, where the memory allocated for it will be popped from the stack, or to allocate a variable on the heap and free it in the next line.
The question is simple. Is it possible to construct such a type T, for which the following two variables declarations will produce different results?
T t1 = {};
T t2{};
I've been digging through the cppreference and the standard for more than an hour now, and I understood the following:
T t2{}; is a value initialization. No surprises here.
T t1 = {} is a list initialization with an empty braced-init-list.
But the last one is tricky since the "effects of list initialization" is an impressive... list. Which for classes, fundamental types and aggregates seems to boil down to value initialization. But I am not sure I haven't missed anything.
Maybe you can provide a context, in which the two declarations will have different effects?
UPD: Excellent answers about explicit constructors! Next level: is it possible that both statements compile, but have different effects on compile/run time?
If you consider a case in which one statement will compile, but the other will not compile as "different effects," then yes, here's a context:
#include <iostream>
class T {
public:
int data{ 0 };
explicit T() {
data = 0;
std::cout << "Default constructor" << std::endl;
}
};
int main()
{
T t1 = {};
T t2{};
return 0;
}
The line declaring/initializing t1 gives the following, with clang-cl:
error : chosen constructor is explicit in copy-initialization
The MSVC compiler also complains:
error C2512: 'T': no appropriate default constructor available
message : Constructor for class 'T' is declared 'explicit'
The difference is in explicit. I've managed to make msvc difference, but it looks like a compiler bug:
#include <iostream>
#include <initializer_list>
struct T
{
template<class... A>
T(A...) {std::cout << "1\n";}
explicit T() { std::cout << "2\n"; }
};
int main()
{
T t1 = {}; // 1
T t2{}; // 2
}
In the old days structure like that:
typedef struct A {
int m_i;
int m_j;
} A;
Allocated on the heap or declared locally in a function without being memset would have its members uninitialized.
However, to my utter surprise this little program shows it is always set to 0.
#include <stdio.h>
typedef struct A {
int m_i;
int m_j;
} A;
void f(const A& a) {
printf("i=%i, j=%i\n", a.m_i, a.m_j);
}
void y() {
f({10});
}
int main() {
y();
return 0;
}
Built using g++ -std=c++11 a.cpp
I would just in case defined a constructor to make sure they are zero, but my various tests show (using code found on the internet) that I don't have to.
Is this a shear coincidence or extended initializer list is a guarantor of having memory being memset?
typedef struct A {
int m_i;
int m_j;
} A;
is an aggregate. When you initialize an aggregate with a braced-init-list it uses each element in the list to initialize each member of the aggregate. If you don't provide enough elements in the braced-init-list then each subsequent member is guaranteed to be value initialized, which for fundamental types means they are zero initialized..
How should I write a constructor for a class to initialize a member that is a const structure / has const fields?
In the following example, I define a constructor within structure B and it works fine to initialize it's const fields.
But when I try to use the same technique to initialize const fields of structure C within class A it doesn't work. Can someone please help me and rewrite my class A in a way, that it starts working?
#include <iostream>
class A
{
public:
struct C
{
C (const int _x) : x (_x) {}
const int x;
};
C c (3);
};
int main (int argc, char *argv[])
{
struct B
{
B (const int _x) : x (_x) {}
const int x;
};
B b (2);
std::cout << b.x << std::endl;
A a;
std::cout << a.c.x << std::endl;
return 0;
}
P.S.
I did some search and I think, I understand, that unless I have C++11 support or want to use boost library, I have to define a helper function to initialize a const struct within initialization list
(C++ Constant structure member initialization)
but it seems to be crazy that I have to define alike struct, but with non const fields to initialize a struct with const fields, doesn't it?
Another thing that I found tells that I should initialize const members in a constructor of the class A, rather than in a constructor of the struct C (C++ compile time error: expected identifier before numeric constant) but it also seems crazy to me, because why should I rewrite a class constructor every time I want to add a new struct, isn't it more convenient to have a separate constructor for each struct C within the class A?
I would be grateful to any comments that could possibly clarify my confusion.
I'd do the job like this:
#include <iostream>
class A {
public:
struct C {
C(const int _x) : x(_x) {}
const int x;
};
C c; // (3);
A() : c(3) {}
};
int main(int argc, char *argv []) {
A a;
std::cout << a.c.x << std::endl;
return 0;
}
Note that it's not a matter of using a ctor in A or in C, but of the ctor for A telling how the ctor for C should be invoked. If the value that will be passed will always be 3 that's not necessary, but I'm assuming you want to be a able to pass a value of your choice when you create the C object, and it will remain constant after that.
If the value will always be the same (3 in this case) you can simplify things a lot by also making the constant static:
struct A {
struct C {
static const int x = 3;
};
C c;
};
int main() {
A a;
std::cout << a.c.x << "\n";
}
So, if the value is identical for all instances of that class, make it static const, initialize it in place, and life is good. If the value is not known until you create an instance of the object, and remains constant thereafter for the life of that object, you need to pass it in through the constructors.
For a slightly different case, there's a third possibility: if C is an independent class (not nested inside of A) you might have a situation where other instances of C use various values, but all instances of C inside an A always use the same value. In this case, you'd do something like:
struct C {
const int x;
C(int x) : x(x) {}
};
struct A {
C c;
A() : c(3) {}
};
Of course, you can do the same thing when C is nested inside of A, but when/if you do, it generally means you're setting the same value for all instances of C, so you might as well use the static const approach instead. The obvious exception would be if A had multiple constructors, so (for example) A's default constructor passed one value for C::x and its copy constructor passed a different value.
#include <initializer_list>
#include <iostream>
using namespace std;
struct Y {};
struct X
{
X(initializer_list<Y>) { cout << "yay" << endl; }
explicit X() { cout << "boo" << endl; }
};
X f()
{
return {};
}
int main()
{
f();
return 0;
}
This prints out "boo". Why doesn't it print out "yay" ?
Is there anyway to differentiate the following two constructions:
X()
X{}
or
return X();
return {};
or
void g(const X&)
g(X())
g({})
Thanks.
Is there anyway to differentiate the following two constructions:
No. They are not different constructs.
The primary purpose of the {} constructor syntax was to introduce uniform initialization, to have initialization work the same everywhere. If there was a difference between them, it wouldn't be uniform.
If you want to use the empty initializer list constructor, you have to state that you're passing an initializer list explicitly. Like this: return initializer_list<Y>{}; Of course, one of the other purposes of uniform initialization is to not have to type out typenames so much, so you can achieve the same effect with return {{}};
return {}; will always use a default constructor if there is one.
return X({}); or return {{}}; will construct from an empty initialiser list.
It uses the default constructor because list initialization with {} is meant to be a short form of value initialization always, disregarding of other constructors, even if they are initializer list constructors.
Is there anyway to differentiate the following two constructions: ...
The X() is always value initialization, while X{} is only value initialization if X has a default constructor. If it is an aggregate, then X{} is aggregate initialization (initializing the members of X by a {} recursively). If it only has initializer list constructors and no default constructors, then X() is invalid and X{} could be valid
struct A { A(initializer_list<int>); };
A a = A{}; // valid
A b = A(); // invalid
Essentially, what X{} does depends on what X is. But X() always value initializes.
... or return X(); vs return {};
Something subtle to mention... In return {} the target is copy-list-initialized, while in return X(); first direct-initializes an X. But even though it is copy-list-initialized, it can use an explicit default constructor, because value initialization doesn't care about explicit. However when you do return {} and you try to use an explicit non-default constructor you will error out
struct A {
explicit A(initializer_list<int>);
};
A f() { return {}; } // error!
struct B {
explicit B();
};
B g() { return {}; } // OK
You could be a bit more explicit:
return initializer_list<Y>();