class object's declaration confucion - c++

whats is the difference between these three statements in c++ ??
aa *obj;
aa *obj1 = new aa;
aa *obj2 = new aa();
where aa is a class
I am confucion in last two statement .

The first does not initialize the pointer.
In the latest specification,
If the new-initializer is omitted, the object is default-initialized (8.5); if no initialization is performed,
the object has indeterminate value.
Otherwise, the new-initializer is interpreted according to the initialization rules of 8.5 for direct initialization.
That is, if the class (you said it was a class) doesn't have a constructor, then the first form will act the same as a local scope definition and leave the memory un-initialized.
The empty initializer will force it to be initialized anyway, which gives the same results as a global variable of that type.
A class might not have a constructor, even a hidden constructor, if it contains nothing but data members of primitive types. You'll see that discussed as a "POD", or plain'ol data. For templates, the difference was found to be annoying, so the rules were refined to work, with (), uniformly for any type, even built-in types. new int() will give a pointer to a value holding 0. new int will give a pointer to a value holding whatever garbage happened to be at that address before.

Related

C++ Pointers and C-style array initialization

Long time java programmer here, new to C++. I have been working with C-style "traditional" arrays (similar to arrays in java). I understand in C++ we can create a simple array as follows:
Person people[3];
The contents of this array is essentially uninitialized junk values. When I print out the contents of each element in the array, I (believe) am getting the memory address of each element.
for(int i = 0; i < 3; i++){std::cout << &person[i] << std::endl;}
Results:
//Note, I get different results here when I use an enhanced for loop vs an iterator for loop. Weird.
00EFFB6C
00EFFBA8
00EFFBE4
Now, here is the part I have failed to get a clear explanation on. I create a pointer to one of the elements in the array. I then ask for some value back from that pointer. In java, I would expect to get a null pointer, but in C++, that is not happening.
Instead, I get the default value, as though this element is initialized:
Person* person1Ptr = &people[0];//Points to an uninitialized value
std::cout << person1Ptr->getFirstName() << std::endl;//Output: "Default First Name", expected nullptr
When I try to get the first name of an element using a reference, this doesn't work (presumably because the value doesn't exist).
Full paste of code: https://pastebin.com/cEadfJhr
From my research, C++ does NOT fill arrays with objects of the specified type automagically.
How is my person1Ptr returning a value?
I believe the problem stems from this misconception :
From my research, C++ does NOT fill arrays with objects of the specified type automagically.
C++ objects have value semantics. Defining a local variable of type T concretely creates a unique instance of that type, it is not a handle to a potential T. The expression Foo f; is conceptually equivalent to the Java expression Foo f = new Foo();. Additionally, value semantics means assignment usually implies a copy. The C++ expression Foo f; Foo g = f; is conceptually equivalent to the Java expression Foo f = new Foo(); Foo g = f.Clone();.
In the case of an array, defining a local variable Foo f[3]; immediately creates three instances of Foo as elements of the f array. Your misconception may come from the fact that creating an object in C++ does not imply that it has been initialized. An object can exist in an uninitialized state. For example int i; create an int object identified by i but its value is indeterminate. In the case of int i[3]; you would have an array of three int each with indeterminate values.
The rules for initialization are very complicated in C++. In the case of Person people[3]; you have an array that is default initialized.
You are initializing an object of type Person[3]. According to default initialization rules :
if T is an array type, every element of the array is default-initialized;
That means each Person gets its own default initialization. To see what happens, consider that T is Person :
if T is a class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object;
So each Person's default constructor will be called to initialize that element. You end up with Person people[3]; defining three default constructed Person objects with default initial values.

Zero initialization of string and string array (C++)

According to https://en.cppreference.com/w/cpp/language/zero_initialization
In the example provided by the documentation:
std::string s; // is first zero-initialized to indeterminate value
// then default-initialized to ""
Why does zero initialization occur to string s; if the syntax is for static T object;?
Why does zero initialization happen before default initialization and why are both allowed to happen?
The effects of zero initialization are:
If T is a scalar type, the object's initial value is the integral
constant zero explicitly converted to T.
If T is an non-union class
type, all base classes and non-static data members are
zero-initialized, and all padding is initialized to zero bits. The
constructors, if any, are ignored.
If T is a union type, the first
non-static named data member is zero-initialized and all padding is
initialized to zero bits.
If T is array type, each element is
zero-initialized
If T is reference type, nothing is done.
What if I initialize string array[2] = {"Test1"};? I know that the array will contain "Test1" and empty string "".
But according to the above documentation,
If T is array type, each element is
zero-initialized
The data type is string which is an object / reference type?
If T is reference type, nothing is done.
Nothing is done? I thought maybe a constructor would have been called. Surely an empty string is something?
(Unless otherwise specified, all declarations in this answer are assumed to be in namespace scope.)
Why does zero initialization occur to string s; if the syntax is for
static T object;?
Why does zero initialization happen before
default initialization and why are both allowed to happen?
Variables with static storage duration are first zero-initialized at compile time, and then optionally dynamically initialized at runtime. static T object; declares an object of static storage duration. For a simple declaration like
int x;
The dynamic initialization is not performed. For a more sophisticated declaration like
std::string s;
Zero-initializing a string may result in an invalid string with a broken class invariant. Therefore, the dynamic initialization calls the default constructor to ensure that the object is valid.
What if I initialize string array[2] = {"Test1"};? I know that the
array will contain "Test1" and empty string "".
First, at compile time, the two objects are zero-initialized, resulting in possible invalid state. Then, at runtime, the constructors are called (const char* constructor for the first object and default constructor for the second object), and the valid objects are constructed.
The data type is string which is an object / reference type?
std::string is an object type instead of a reference type.
[For a reference type] Nothing is done? I thought maybe a constructor
would have been called. Surely an empty string is something?
A reference type is not considered an actual "object", so there is no point in specifying its zero-initialization semantics.
Why does zero initialization occur to string s; if the syntax is for static T object;?
Why does zero initialization happen before default initialization and why are both allowed to happen?
In page you linked to, that defines a non-local variable.
Non-local variables are initialized in two phases.
Static intialization.
Dynamic initialization, if it applies.
In static initialization phase, a variable is initialized using constant initialization or zero initialization
Dyanmic initialization is used, if it applies, such as for objects that have the appropriate constructor or for objects that are initialized using an expression that can be evaulated at run time.
You can read more on the topic at https://en.cppreference.com.
Nothing is done? I thought maybe a constructor would have been called. Surely an empty string is something?
A reference cannot be zero-initialized. It can only be initialized using a object that it will be a reference to.

int x; int y; int *ptr; is not initialization, right?

I'm reading 'C++ All-in-One for Dummies' by J. P. Mueller and J. Cogswell and stumbled onto this:
#include <iostream>
using namespace std;
int main()
{
int ExpensiveComputer;
int CheapComputer;
int *ptrToComp;
...
This code starts out by initializing all the goodies involved — two integers
and a pointer to an integer.
Just to confirm, this is a mistake and should read '... by declaring', right? It's just strange to me that such basic mistakes still make their way to books.
From the point of view of the language, this is default initialization. The problem is, they are initialized to indeterminate values.
otherwise, nothing is done: the objects with automatic storage duration (and their subobjects) are initialized to indeterminate values.
Default initialization of non-class variables with automatic and dynamic storage duration produces objects with indeterminate values (static and thread-local objects get zero initialized)
Note that any attempt to read these indeterminate values leads to UB.
From the standard, [dcl.init]/7
To default-initialize an object of type T means:
If T is a (possibly cv-qualified) class type ([class]), constructors are considered. The applicable constructors are enumerated
([over.match.ctor]), and the best one for the initializer () is chosen
through overload resolution ([over.match]). The constructor thus
selected is called, with an empty argument list, to initialize the
object.
If T is an array type, each element is default-initialized.
Otherwise, no initialization is performed.
Yes you are correct.
You declared and defined these variables, you did not initialize them!
PS: What is the difference between a definition and a declaration?
This code both declares and defines three variables but does not initialize them (their values are said to be indeterminate).
A variable declaration only must include keyword extern.
Right. Hence, "dummies". :)
We can't even blame this on legacy; historically C programmers would declare* a variable and then "initialize" it later with its first assignment.
But it was never the case that simply declaring a variable, without an initializer, were deemed to be "initializing" it.**
So the wording is just wrong.
* Technically we're talking about definitions, but when we say "declare a variable" we almost always mean defining declarations.
** Though objects with static storage duration do undergo their own zero-initialisation phase before anything else happens, so forgoing initialisation yourself is not a catastrophe in that case. Still, we cannot claim that we have initialised that object.

After an object is destroyed, what happens to subobjects of scalar type?

Consider this code (for different values of renew and cleanse):
struct T {
int mem;
T() { }
~T() { mem = 42; }
};
// identity functions,
// but breaks any connexion between input and output
int &cleanse_ref(int &r) {
int *volatile pv = &r; // could also use cin/cout here
return *pv;
}
void foo () {
T t;
int &ref = t.mem;
int &ref2 = cleanse ? cleanse_ref(ref) : ref;
t.~T();
if (renew)
new (&t) T;
assert(ref2 == 42);
exit(0);
}
Is the assert guaranteed to pass?
I understand that this style is not recommended. Opinions like "this is not a sound practice" are not of interest here.
I want an answer showing a complete logical proof from standard quotes. The opinion of compiler writers might also be interesting.
EDIT: now with two questions in one! See the renew parameter (with renew == 0, this is the original question).
EDIT 2: I guess my question really is: what is a member object?
EDIT 3: now with another cleanse parameter!
I first had these two quotes, but now I think they actually just specify that things like int &ref = t.mem; must happen during the lifetime of t. Which it does, in your example.
12.7 paragraph 1:
For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.
And paragraph 3:
To form a pointer to (or access the value of) a direct non-static member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.
We have here a complete object of type T and a member subobject of type int.
3.8 paragraph 1:
The lifetime of an object of type T begins when:
storage with the proper alignment and size for type T is obtained, and
if the object has non-trivial initialization, its initialization is complete.
The lifetime of an object of type T ends when:
if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or
the storage which the object occupies is reused or released.
By the way, 3.7.3 p1:
The storage for these [automatic storage duration] entities lasts until the block in which they are created exits.
And 3.7.5:
The storage duration of member subobjects, base class subobjects and array elements is that of their complete object (1.8).
So no worries about the compiler "releasing" the storage before the exit in this example.
A non-normative note in 3.8p2 mentions that "12.6.2 describes the lifetime of base and member subobjects," but the language there only talks about initialization and destructors, not "storage" or "lifetime", so I conclude that section does not affect the definition of "lifetime" for subobjects of trivial type.
If I'm interpreting all this right, when renew is false, the lifetime of the complete class object ends at the end of the explicit destructor call, BUT the lifetime of the int subobject continues to the end of the program.
3.8 paragraphs 5 and 6 say that pointers and references to "allocated storage" before or after any object's lifetime can be used in limited ways, and list a whole lot of things you may not do with them. Lvalue-to-rvalue conversion, like the expression ref == 42 requires, is one of those things, but that's not an issue if the lifetime of the int has not yet ended.
So I think with renew false, the program is well-formed and the assert succeeds!
With renew true, the storage is "reused" by the program, so the lifetime of the original int is over, and the lifetime of another int begins. But then we get into 3.8 paragraph 7:
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:
the storage for the new object exactly overlays the storage location which the original object occupied, and
the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
the original object was a most derived object (1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).
The first bullet point here is the trickiest one. For a standard-layout class like your T, the same member certainly must always be in the same storage. I'm not certain whether or not this is technically required when the type is not standard-layout.
Although whether ref may still be used or not, there's another issue in this example.
12.6.2 paragraph 8:
After the call to a constructor for class X has completed, if a member of X is neither initialized nor given a value during execution of the compound-statement of the body of the constructor, the member has indeterminate value.
Meaning the implementation is compliant if it sets t.mem to zero or 0xDEADBEEF (and sometimes debug modes will actually do such things before calling a constructor).
You have not destroyed memory, you only manually called destructor (in this context it's not different then calling normal method). Memory (stack part) of your t variable was not 'released'. So this assert will always pass with your current code.

How are local and global variables initialized by default?

Based on below, am i right?
global_A reference is initialized to null.
global_int is 0
local_A reference is null
local_int is uninitialized
Both global_A.x and local_A.x is uninitialized.
THanks for any help.
A global_A;
int global_int;
class A {
public : int x;
}
int main()
{
int local_int;
A local_A;
}
Building up on Andrey's response.
$3.6.2- "Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place.". In OP, "global_A" and "global_int" have static storage duration. "local_int" and "local_A" have no linkage as these are local objects.
$8.5/5- 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
zeroinitialized;
— if T is a union type, the object’s
first named data member89) is
zero-initialized;
— if T is an array type, each element
is zero-initialized;
— if T is a reference type, no
initialization is performed.
$6.7.4/4- "The zero-initialization (8.5) of all local objects with static storage duration (3.7.1) is performed before any other initialization takes place. A local object of POD type (3.9) with static storage duration initialized with constant-expressions is initialized before its block is first entered. An implementation is permitted to perform
early initialization of other local objects with static storage duration under the same conditions that an implementation is permitted to statically initialize an object with static storage duration in namespace scope(3.6.2). Otherwise such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control re-enters the declaration (recursively) while the object is being initialized, the behavior is undefined."
EDIT 2:
$8.5/9- "If no initializer is
specified for an object, and the
object is of (possibly cv-qualified)
non-POD class type (or array thereof),
the object shall be
default-initialized; if the object is
of const-qualified type, the
underlying class type shall have a
user-declared default constructor.
Otherwise, if no initializer is specified for a nonstatic object, the
object and its subobjects, if any,
have an indeterminate initial
value90); if the object or any of
its subobjects are of const-qualified
type, the program is ill-formed."
In general, you want to read up these sections along with $8.5 for good hold on this aspect.
There are no references in your code, so any of your points that mention "references" make no sense.
In your example, both global object - global_int and global_A - are zero-initialized. Both local objects - local_int and local_A - contain indeterminate values, which means that local_int and local_A.x are not initialized.
P.S. Of course, as other already noted, your code is non-compilable. You can't declare A objects before declaring class A (and you are missing a ; after the class definition).
Basically, whenever you declare a variable, the compiler will call its default constructor unless you specify otherwise.
The language level types (e.g. pointers, 'int', 'float', 'bool', etc) "default constructor" does absolutely nothing, it just leaves the memory as it is when it is declared (global/static variables are special cases, refer to chubsdad's answer for more on the specifics). This means that they can be pretty much anything because you usually can't be sure what was in that memory previously or even where the memory came from (except in the case of the 'placement new' operator).
The class you created has no constructors so the compiler will generate a default constructor for you which simply calls the constructor of each of its members/variables. If you incorporate the information provided in the previous paragraph, you can see that the variable 'x' will have its default constructor called, which does nothing, and thus is isn't initialized to any value.
As others have said, there are no references in your code or pointers, so the term 'NULL' is invalid in all cases here. NULL usually refers to a pointer which, like other language level types, doesn't get set to anything until you assign it a value (unless of course its a global/static variable).
Just for the sake of completeness if you had references:
References must be initialized on declaration, otherwise you get punished by a compiler error. This means a reference always needs another value or reference it refers to (like the says), this is ensured by the compiler so you cannot forget it. This also implies that references can never be null pointers. However the object they refer to might become invalid.
global_A and local_A are not references; they are objects and created using their default constructors. Default constructor has not been specified so it will be generated, which will do nothing so the member variable will remain uninitialized.
A global_A;
This is an instace, not a pointer, your program will call the constructor before entering main.
To get a pointer to an instance and not an instance you have to write:
A* global_A;
global_int is initialized to 0, as all global variables are initialized to their defaults.
The variable A local_A will be initialized every time your program enters the function in which it is declared by a call to its constructor.
As before if you want a pointer to A you have to write A *local_A, but this time you have to initialize it to NULL yourself.
A *local_A = NULL;
The varialle local_int wont be initialized as it is a primitive type.
If local_A.x is initialized depends on the constructor of A, the default constructor will not initialize local_A.x. If x where a class instance creating an instance of A will initialize x with the constructor of its class.
They all require to be initialized. The compiler will give you a warning about this.
This code won't compile unless you forward declare A.
global_A reference is initialized to null - No, it will reference an A object.
global_int is 0 - Think so, need to check.
local_A reference is null - No, same as with global_A.
local_int is uninitialized - Yes, it will get some garbage value.
Both global_A.x and local_A.x is uninitialized - Yes.
You can always debug and see for yourself.
well guys .. i am more confused as i see responses from here. Anyway i did a test as shown below:
1 #include
2 using namespace std;
3
4 class A {
5
6 public :
7 A() : x(9) {};
8 int x;
9
10 };
11
12 A global_a;
13 int global_b;
14
15 int main() {
16
17 A local_a;
18 int local_b;
19 cout << "global_a.x = " << global_a.x << '\n';
20 cout << "local_a.x = " << local_a.x << '\n';
21
22 cout << "global_b = " << global_b << '\n';
23 cout << "local_b = " << local_b << '\n';
24
25 }
Results using my g++ compiler on ubuntu linux:
global_a.x = 9
local_a.x = 9
global_b = 0
local_b = 0
I do think local_b should be undefined but somehow compiler initialized it by default. However local_a .. i am not sure if that should be initialized by default. From the testing here .. local_a seem to be initialized. Not sure if that complies with standard c++ specification (eg C++ PRimer 4th edition says default constructor is used regardless where a class variable is declared - does that means variable of class type is initialized whether it is global or local?).
Whatever it is .. it is one big hell of confusion. Maybe i should quit learning C++. Java is so much more straight forward. Hell yeahhh!!
global_A reference is initialized to
null.
No, its a valid object (constructed based on default constructor, which you don't have in your code but compiler adds that)
global_int is 0
yes
local_A reference is null
no, same reason as for global
local_int is uninitialized
no, its initialized to 0
Both global_A.x and local_A.x is
uninitialized.
no both are initialized to 0