C++ class instantiation theory - c++

#include <iostream>
using namespace std;
class A {
public:
A() {
cout << "Default Ctor" << endl;
}
};
int main() {
A(); // <------- Problem
return 0;
}
It shows Default Ctor on console. My questions
Is is valid?
If so, how did it instantiate since I didn't use new or any object?

You are creating a new object with A().
Is is valid?
Yes it is.
If so, how did it instantiate since I didn't use new or any object?
new simply creates the object in dynamic memory. You're creating the object in automatic memory. Also, just because you didn't give the object a name, doesn't mean it isn't created.
Think of this:
int foo() { return 1; }
int main()
{
foo();
}
Leaving optimizations aside Did foo() actually return 1? Yes it did. Just that you're not using it.
EDIT:
Let's break it down a bit:
A(); //creates a temporary unnamed object in automatic storage
A a; //creates an object a of type A in automatic storage
A a(); //creates no object, but declare a function a returning A and taking no parameters
A a(A()); //these two are equivalent
A a = A(); //creates a temporary unnamed object and creates an object a in automatic storage
//using the compiler-generated copy constructor
A a;
a = A(); //creates an object a in automatic storage
//creates an unnamed temporary object and uses the compiler-generated assignment operator
//to assign it to a
A a = &A(); //invalid, &A() is the address of a temporary a, which is illegal

Is is valid?
Yes, It is valid
What exactly happens?
A();
Creates a temporary nameless object of the type A by calling its default no argument constructor but the object is destructed by the time the next statement is executed since.
If so, how did it instantiate since I didn't use new or any object?
You can create objects on the local/automatic storage or on dynamic storage depending on your usage.
When you use new objects are created on dynamic storage(heap), when you create a object as you have it is created on the local/automatic storage(stack).
So using new only determines where the object will be created not whether it will be created.
What are Temporary Nameless objects?
You do not always need to name an object to instantiate them.
For Ex:
While calling function, when you pass objects by value temporary nameless objects are created and automatically destroyed all the time.These are objects which do not have any name and hence cannot be explicitly referred through program but they do serve the purpose for which they were created.
In simple words,
You are creating a nameless temporary object on the local/automatic storage which does not exist once the statement completes execution.

Related

Overwrite stack-allocated instance of a class

Consider the following code:
class A{
public:
A(){};
};
int main(){
A a = A();
std::cout << &a << std::endl;
a = A();
std::cout << &a << std::endl;
return 0;
}
Both addresses are the same. The behavior that I expected was that the second call to A() would overwrite the variable a by creating a new instance of A, thereby changing the new address of a.
Why is this so? Is there a way to statically overwrite a that I am not aware of?
Thank you!
Why is this so?
Within the scope of its lifetime, a variable is exactly one complete object (except in the case of recursion in which case there are multiple overlapping instances of the variable). a here is the same object from its declaration until the return of the function.
I expected was that the second call to A() would overwrite the variable a by creating a new instance of A,
It did that.
thereby changing the new address of a.
It didn't do that. The temporary object created by A() had a new address, but that temporary object was destroyed at the end of that full expression. a remained where it had been, and you invoked its assignment operator with the temporary object as the argument.
The variable a is allocated on the stack. Its address is not going to change for the duration of the function. The first and the second instance of class A will be created in the space taken up but the variable.

Are there only two ways to create new objects in C++? (using and without using the `new` keyword)

Unless I'm mistaken,
Rectangle rect(3,4); which calls Rectangle's constructor with 3 and 4 as arguments, but does not assign the created object to pointer or reference or variable or anything.
and
Rectangle* rect = new Rectangle(3,4); creates an object and a pointer to that object (new always returns a pointer, which is why the type is a pointer to rectangle and not just rectangle. I think.)
Other than those two ways, is there any way to create and object? And am I misunderstanding anything about object initialization?
Edit: sorry, typo, rect is a variable, but it isn't a pointer or reference.
No, there are more ways to create new objects in C++.
From the C++ 17 standard (intro.object/1):
An object is created by a definition, by a new-expression, when implicitly changing the active member of a union, or when a temporary object is created.
Examples:
struct Rectangle {
Rectangle(int x, int y);
int x, y;
};
Rectangle rect(3,4); // object created by definition. Object has static storage duration
void fun() {
Rectangle rect(3,4); // object created by definition. Object has automatic storage duration
new Rectangle(3,4); // object created by new expression Object has dynamic storage duration. Note, it is possible to create object without assigning it to any pointer or reference
}
int temp() {
return Rectangle(1, 2).x; // temporary object created with automatic storage duration
// this is just an example and it is not the only way to create temporary object
}
// Following code can be skipped if you don't know about unions yet
struct A {
int x;
};
union B {
A a;
int z;
};
void test() {
B b;
b.a.x = 5; // Creates b.a object.
}
There are 4 ways to create an object, listed in [intro.object]/1:
An object is created by a definition, by a new-expression, when implicitly changing the active member of a union, or when a temporary object is created. [...]
bold mine

Memory during Initializing using 'equal to' sign

I am trying to understand the memory used in a particular type of initialization. Here is an example for the question:
#include <iostream>
using namespace std;
class Example {
int n;
public:
Example(int number = 0)
{
n = number;
}
};
int main() {
Example *obj1 = new Example(1); //dynamic allocation - 1 instance is created and the object pointer points to the address
Example obj2(2); // automatic allocation - a single instance of the object is created with the given value
Example obj3 = Example(3); //automatic allocation - with copy constructor from an object initialized with a the class constructor
delete obj1; //de-allocating dynamically allocate memory
}
I am interested in knowing how obj3 is being instantiated. Does the usage of the equal to sign mean that we are using a copy constructor here? If so, is Example(3) a separate instance (what is its scope)?
If they are separate instances, then it seems the initialization of obj2 more optimized, isn't it?
Edit: Fixed usage of incorrect terminology - static to automatic
I am interest in knowing how obj3 is being instantiated. Does the usage of the equals to sign mean that we are using a copy constructor here? If so, is Example(3) a separate instance (what is its scope)?
This expression is known as copy initialization and your case with obj3 dsescribed here:
First, if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather than a temporary materialized from it, is used to initialize the destination object: see copy elision (since C++17)
So no copy ctor involved and obj3 is initialized directly (passing 3 to its ctor) for the current standard. Before C++17 temporary could be created but most probably it would be eliminated by optimizer.
Note: you incorrectly stated in comment for automatic variables to use static memory allocation. Please see details here Difference between static memory allocation and dynamic memory allocation

Is it allowed to call destructor explicitly followed by placement new on a variable with fixed lifetime?

I know that calling destructor explicitly can lead to undefined behavior because of double destructor calling, like here:
#include <vector>
int main() {
std::vector<int> foo(10);
foo.~vector<int>();
return 0; // Oops, destructor will be called again on return, double-free.
}
But, what if we call placement new to "resurrect" the object?
#include <vector>
int main() {
std::vector<int> foo(10);
foo.~vector<int>();
new (&foo) std::vector<int>(5);
return 0;
}
More formally:
What will happen in C++ (I'm interested in both C++03 and C++11, if there is a difference) if I explicitly call a destructor on some object which was not constructed with placement new in the first place (e.g. it's either local/global variable or was allocated with new) and then, before this object is destructed, call placement new on it to "restore" it?
If it's ok, is it guaranteed that all non-const references to that object will also be ok, as long as I don't use them while the object is "dead"?
If so, is it ok to use one of non-const references for placement new to resurrect the object?
What about const references?
Example usecase (though this question is more about curiosity): I want to "re-assign" an object which does not have operator=.
I've seen this question which says that "overriding" object which has non-static const members is illegal. So, let's limit scope of this question to objects which do not have any const members.
First, [basic.life]/8 clearly states that any pointers or references to the original foo shall refer to the new object you construct at foo in your case. In addition, the name foo will refer to the new object constructed there (also [basic.life]/8).
Second, you must ensure that there is an object of the original type the storage used for foo before exiting its scope; so if anything throws, you must catch it and terminate your program ([basic.life]/9).
Overall, this idea is often tempting, but almost always a horrible idea.
(8) 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:
(8.1) the storage for the new object exactly overlays the storage location which the original object occupied, and
(8.2) the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
(8.3) 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
(8.4) 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).
(9) If a program ends the lifetime of an object of type T with static (3.7.1), thread (3.7.2), or automatic (3.7.3) storage duration and if T has a non-trivial destructor, the program must ensure that an object of the
original type occupies that same storage location when the implicit destructor call takes place; otherwise the behavior of the program is undefined. This is true even if the block is exited with an exception.
There are reasons to manually run destructors and do placement new. Something as simple as operator= is not one of them, unless you are writing your own variant/any/vector or similar type.
If you really, really want to reassign an object, find a std::optional implementation, and create/destroy objects using that; it is careful, and you almost certainly won't be careful enough.
This is not a good idea, because you can still end up running the destructor twice if the constructor of the new object throws an exception. That is, the destructor will always run at the end of the scope, even if you leave the scope exceptionally.
Here is a sample program that exhibits this behavior (Ideone link):
#include <iostream>
#include <stdexcept>
using namespace std;
struct Foo
{
Foo(bool should_throw) {
if(should_throw)
throw std::logic_error("Constructor failed");
cout << "Constructed at " << this << endl;
}
~Foo() {
cout << "Destroyed at " << this << endl;
}
};
void double_free_anyway()
{
Foo f(false);
f.~Foo();
// This constructor will throw, so the object is not considered constructed.
new (&f) Foo(true);
// The compiler re-destroys the old value at the end of the scope.
}
int main() {
try {
double_free_anyway();
} catch(std::logic_error& e) {
cout << "Error: " << e.what();
}
}
This prints:
Constructed at 0x7fff41ebf03f
Destroyed at 0x7fff41ebf03f
Destroyed at 0x7fff41ebf03f
Error: Constructor failed

Persistance of object instances that are created inside methods in C++

Lets say I have a simple class that simply holds an object:
class objholder{
object ojb;
public:
setobj(object o);
}
objholder::setobj(object o){
obj = o;
}
objholder::getobj(){
return obj;
}
Lets say I create a function that creates an instance of an object which then gets passed to the objholder.
What happens to the instance of the object when the function returns? Does it persists?
What happens if I then try to access the instance of object that has been saved by the objholder will it stil contain a valid reference?
Here are some simple functions that illustrate the functionality I've described above.
void foo(objholder oh){
object temp;
oh.setobj(temp);
}
void bar(objholder oh){
object temp = oh.getobj();
}
int main(int argc, char **argv){
objholder o;
foo(o);
bar(o);
}
C++ is a language value semantics, which means that by default types are treated as values, copied, etc. unlike Java or C# that have reference semantics. Lets analyze the program:
void foo( objholder );
int main(int argc, char **argv){
objholder o; // [1]
foo(o); // [2]
bar(o); // [3]
}
void foo( objholder oh ) { // [4]
object tmp; // [5]
oh.setobject( tmp ); // [6]
} // [7]
In [1] a new object o is created in the scope of main. That object contains a subobject obj of type object initialized as per objholder default constructor. In [2] a copy of that object is done and passed to foo ([4]) that creates a local object ([5]) that is passed to the setobject member method of oh in [6], (remember: oh is a copy of the objholder in main), because objholder::setobject takes the element by value, a copy of tmp is created, and that copy is passed to oh.setobject, that in turn makes a copy and stores it in the member attribute (not shown in the code). In [7] the execution of foo completes and all local variables are destroyed in reverse order of creation, which means that tmp is destroyed, and then oh (which in turn means that the internal copy of tmp is destroyed).
At this point we are back in main where our local object o has remained untouched --all that has been processed was the copy passed to foo. Then as in the call to foo a copy is created and passed to bar.
I started noting that this is due to the value semantics in C++, compared with reference semantics in other languages as Java or C#. If the program was (syntax aside) Java, in [2] and [3] a copy of the reference would be passed, and the referred object both in main, foo and bar would be the same. This can be achieved in C++ by using pointers and references. C++ references are not just like Java/C# references, so if you come from any of those languages take time to understand the similarities and differences.
What happens to the instance of the object when the function returns? Does it persists?
It's destroyed along with the holder. But note that your objectholder copies the object passed to its setobj.
What happens if I then try to access the instance of object that has been saved by the objholder will it stil contain a valid reference?
Do you mean...
object obj;
{
objectholder holder;
holder.setobj(obj);
}
// do something to obj
? Nothing special happens (except if object does something special in its copy constructor).
The way you have done your objholder you are not "holding" the object, merely holding a copy of the object.
this just makes a copy of 'o' and stores it in 'obj'
objholder::setobj(object o)
{
obj = o;
}
if you want to keep a reference to the object you need to either pass a reference or a pointer to the object
object& obj;
objholder::setobj(object& o)
{
obj = o;
}
however by keeping a reference to object you are still not owner of the object (if i understood correctly is what you are getting at), instead you would need to use unique_ptr to take ownership of the object. By using unique_ptr you can sort of pass an object around.
that said, in order to understand life of object you should look into scopes and the free store/stack.