Expected 2 calls to the destructor but got only 1 - c++

I was studying how a function returns an object by means of return-by-value. So, to test the theory, I ran a simple program that had a function returning an instance of myclass - a custom-made class.
#include <iostream>
#include <cstdio>
using namespace std;
class myclass {
int i;
public:
void set_i(int n) { i=n; }
~myclass();
};
myclass f(int k); // return object of type myclass
int main()
{
f(20);
return 0;
}
myclass f(int k)
{
myclass x;
x.set_i(k);
return x;
}
myclass::~myclass() {
cout << "hello\n";
}
I overloaded the destructor by placing a cout "hello" statement in it so that I would be able to track when the object's local copy within the function as well as the temporary object created during execution of the return statement were destroyed.
So, I was expected 2 calls to the destructor; one for the function's local copy of the object and one for the temporary object. But instead, I received only one!
Please share why my program did not output "hello" twice.
Thanks.

That is an effect of return value optimization which eliminates the temporary object created to hold a function's return value. This optimizes out the redundant copy constructor and destructor calls.

Related

Return optional from class method

I have a optional member in a class, which I want to return by value, via a method.
Sample code:
#include <stdio.h>
#include <optional>
#include <iostream>
using namespace std;
class bar {
public:
int a;
bar(const bar &obj) {
a = obj.a;
}
};
class foo {
public:
void init(){
abc->a = 100;
}
optional<bar> get() {
return abc;
}
optional<bar> abc;
};
int main()
{
foo temp;
temp.init();
auto copied = temp.get();
cout << "Expected value is 100, got: " << copied->a;
return 0;
}
The code outputs some garbage value.
How may I achieve this?
From my understanding, optional stores a fully allocated memory for the underlying type (not just a reference), and while returning a optional variable, the copy constructor of the underlying type should kick in, which should copy the memory as-is to the new optional value being returned.
You need to use the constructor of optional to ensure that it contains an object: (assuming that the redundant copy constructor of bar, which blocks it from being constructed, is removed)
foo()
: abc{bar{100}}
{
}
or, after the optional has been created:
void init(){
abc = bar{100};
}
Otherwise, the optional is kept in an empty state, and invoking -> on an empty optional results in undefined behavior. The copy constructor of optional does not copy construct a contained object when the source is empty.
std::optional is like a smart pointer, it defaults to a "null" value and accessing its members would therefore be undefined behaviour. You need to initialise it before use:
void init(){
abc = bar();
abc->a = 100;
}
Note that as it stands bar isn't constructible other than via the copy constructor so you need to add a default constructor or a constructor that takes an int argument or remove the unnecessary copy constructor.

Memory allocation of returned object in c++

What happens to the object returned from the last line of following code
class weight
{
int kilogram;
int gram;
public:
void getdata ();
void putdata ();
void sum_weight (weight,weight) ;
weight sum_weight (weight) ;
};
weight weight :: sum_weight(weight w2)
{
weight temp;
temp.gram = gram + w2.gram;
temp.kilogram=temp.gram/1000;
temp.gram=temp.gram%1000;
temp.kilogram+=kilogram+w2.kilogram;
return(temp);
}
int main(){
//.....//
w3=w2.sum_weight(w1);
w2.sum_weight(w1);
//.....//
}
Does it remains in the memory till completion or it gets deleted.
Let's try to look at what actually happens:
#include <stdio.h>
class A {
public:
A() { printf("default constructing at %016zx\n", (size_t)this); }
A(const A& a) { printf("copy constructing from %016zx at %016zx\n", (size_t)&a, (size_t)this); }
void operator=(const A& a) { printf("assigning from %016zx to %016zx\n", (size_t)&a, (size_t)this); }
~A() { printf("destructing at %016zx\n", (size_t)this); }
static A makeA() {
A temp;
return temp;
}
};
int main() {
A a;
printf("calling makeA()\n");
a = A::makeA();
printf("returned from makeA()\n");
}
This code produces the following output on my machine (no compiler optimizations!):
default constructing at 00007ffe39415d0e
calling makeA()
default constructing at 00007ffe39415d0f
assigning from 00007ffe39415d0f to 00007ffe39415d0e
destructing at 00007ffe39415d0f
returned from makeA()
destructing at 00007ffe39415d0e
So, you see, during the call the variable in makeA() is created, the value of the variable in makeA() is assigned to the variable in main(), and the variable in makeA() is destroyed. The variable in main() is created before the call and remains valid until main() returns to its caller.
sum_weight(w1); will return a object but you are not assigning it means object never used. In the first case w3=w2.sum_weight(w1); it will call the assignment operator as well as a copy constructor and default constructor ( i.e. temp)
. In the second case two instances of weight (first one (weight w2) and second one weight temp;) will be created. Hance just before exiting from the main method O/S will call the destructors of both the object. W3 and the temporary object created from the statement w2.sum_weight(w1); ( i.e. temp)

Weird constructors behavior

#include <iostream>
using namespace std;
class Foo
{
public:
Foo()
{
cout << 0;
}
Foo(Foo &f)
{
cout << 1;
}
};
void someFunction(Foo f) {};
int main()
{
Foo f1; //displays 0 (as expected)
Foo f2(f1); //displays 1 (as expected)
someFunction(f1); //displays 1 (why?)
someFunction(f2); //displays 1 (why?)
return 0;
}
I don't understand why function 'someFunction' calls second constructor. I thought it will just call first constructor, with no parameters, and displays 0.
Maybe I am missing something obvious...
The second constructor is a copy constructor, and when you pass an argument to a function by value it is copied, which invokes the copy constructor.
The first constructor (the default constructor) is only called when creating an object from scratch, and without any arguments.
Because when you call someFunction, the compiler invokes the copy-constructor to copy the object f1 or f2 into f.
To avoid that, just declare the function with a reference parameter to a Foo object, like so:
int someFunction(Foo &f) {}
Then call it as usual:
someFunction(f1);
It will never call default constructor because you are just copying foo object. It will use copy constructor and if there is no copy contructor available, it is using the second which is similar to that.

Simulate a virtual copy constructor

I am a newbie to c++ and just learning by reading a book.
So the question may be a bit stupid.
Here is my program:
#include <iostream>
using namespace std;
class Fish
{
public:
virtual Fish* Clone() = 0;
};
class Tuna : public Fish
{
public:
Tuna(const Tuna& SourceTuna)
{
cout << "Copy Constructor of Tuna invoked" << endl;
}
Tuna* Clone()
{
return new Tuna(*this);
}
};
I have question on
return new Tuna(*this);
First, why does the copy constructor return a pointer of Tuna?
Usually, invoking the copy constructor will return a copied instance directly.
For example:
class Student
{
public:
Student(){}
Student(const Student& Input) { cout << "Copy Ctor Invoked\n"; }
};
int main()
{
Student a;
Student b(a);
return 0;
}
Base on my understanding, what Student b(a); does is copying an instance of a and named b.
So why does new Tuna(*this) is not returning an instance instead of a pointer?
Second, why is point of this,ie. *this , provided in the argument?
Base on my understanding this is a pointer to the current object, which mean *this is a pointer to the pointer of the current object. I try to use int to simulate the situation.
// The input argument is the same as a copy constructor
int SimulateCopyConstructor(const int& Input){ return 0; }
void main()
{
int a = 10; // a simulate an object
int* b = &a; // b is a pointer of object a, which simulate "this"
int** c = &b; // c is a pointer to pointer of object a, which simulate of "*this"
SimulateCopyConstructor(a); // It can compile
SimulateCopyConstructor(b); // cannot compile
SimulateCopyConstructor(c); // cannot compile
}
I think sending (*this) to copy constructor is similar to the situation c above. But it does not compile. So how does it works?
Student b(a);
Does not return a Student object. It declares it and instructs compiler to call a copy contructor on the new object allocated on stack.
new Student(a);
This indeed returns a pointer to a new Student object because operator new does. And (a) there instructs the compiler to call a copy contructor on that object that was allocated by new.
However if you had a function doing this:
Student foo(){ return Student(a); }
That would create a new Student object on stack, call copy constructor and then return the resulting object from the function.

Is this code behavior well-defined?

Here's some C++ code:
#include <iostream>
class A
{
int x;
int y;
double v;
public:
A(int x, int y)
:x(x),y(y)
{
std::cerr << "A("<<x<<","<<y<<")\n";
}
~A()
{
std::cerr << "~A()\n";
}
operator double* ()
{
v=1.5*x+y;
return &v;
}
};
void f(double* val)
{
std::cerr << "f("<<*val<<")\n";
*val=0.3;
}
int main()
{
f(A(3,5));
}
I get the following as output:
A(3,5)
f(9.5)
~A()
I.e. as I'd like it to work. But I'm not sure whether destructor of A must be called after f returns. Is it guaranteed? Can the pointer returned by operator double* () somehow become invalid in the call of f?
You are declaring an A object as an actual parameter of f, when you do that, for all effects the new object is like a local variable of f so ~A is guaranteed to be called at the end of f execution.
If f returns the address returned by operator double* () and it is used after f has returned you will be accessing to invalid memory. One way to avoid this situation is making double v static but you have to consider that, in your code, the A class created object only exits while f block is running.
The arguments to a function are evaluated before the function is invoked, and the temporaries will live to the end of the full expression that they are in. So yes, the instance of A will live to just past the end of the invocation of f.