In this example, why is it ok to return a stack variable? When t() returns, why is it not returning garbage, since the stack pointer has been incremented?
#include << string >>
#include << vector >>
#include << iostream >>
using namespace std;
class X{
public:
X() { cout << "constructor" << endl; }
~X() { cout << "destructor" << endl; }
};
vector <X> t()
{
cout << "t() start" << endl;
vector<X> my_x;
int i = 0;
printf("t: %x %x %x\n", t, &my_x, &i);
my\_x.push\_back(X()); my\_x.push\_back(X()); my\_x.push\_back(X());
cout << "t() done" << endl;
return my_x;
}
int main()
{
cout << "main start" << endl;
vector <X> g = t();
printf("main: %x\n", &g);
return 0;
}
output:
./a.out
main start
t() start
t: 8048984 bfeb66d0 bfeb667c
constructor
destructor
constructor
destructor
destructor
constructor
destructor
destructor
destructor
t() done
main: bfeb66d0
destructor
destructor
destructor
Basically when you return the stack variable my_x you would be calling the copy constructor to create a new copy of the variable. This is not true, in this case, thanks to the all mighty compiler.
The compiler uses a trick known as return by value optimization by making the variable my_x really being constructed in the place of memory assigned for g on the main method. This is why you see the same address bfeb66d0 being printed. This avoids memory allocation and copy construction.
Sometimes this is not at all possible due to the complexity of the code and then the compiler resets to the default behavior, creating a copy of the object.
Because parameters are passed by value. A copy is made. So what is being returned is not the value on the stack, but a copy of it.
Well a copy is returned, the only construct you can not return a copy of it is a static array. So you can not say this...
int[] retArray()
{
int arr[101];
return arr;
}
The compiler is optimized to handle returning "stack variables" without calling the copy constructor. The only thing you need to know about is that that memory allocation is in scope of both the function that allocated it on the stack and the function that the object is returned to.
It does NOT call the copy constructor nor does it allocate it twice.
There may be some special cases and of course it depends on the compiler -- for example, primitives may be copied -- but in general, objects allocated on the stack, don't get copied when being returned.
Example:
struct Test {
};
Test getTest() {
Test t;
std::cout << &t << std::endl; // 0xbfeea75f
return t;
}
int main(int argc, char *argv[])
{
Test t = getTest();
std::cout << &t << std::endl; // also 0xbfeea75f
}
Related
I am trying to assign a variable to a return value but the deconstructor is called before the values are assigned to pq. I also get the following error which I'm assuming is an attempt to double delete a variable:
_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
PriorityQueue pq;
pq = FindThroughPaths(a, b);
FindThroughPaths(a, b) returns a PriorityQueue.
I may be getting this error because the return value has dynamically allocated member variables.
I am simply trying to find a way to keep the return value of FindThroughPaths(a, b) within the scope and I do not want to create multiple instances just to access it's members. This is an example of what I would like:
PriorityQueue pq;
pq = FindThroughPaths(a, b);
while (!pq.IsEmpty) {
Path tmp = pq.Dequeue();
std::cout << "\n" << tmp.name << " #" << tmp.number;
}
The constructor, deconstructor, and assignment operator for PriorityQueue:
PriorityQueue::PriorityQueue()
{
std::cout << "\nConstructor called." << endl;
items.elements = new ItemType[maxItems];
length = 0;
}
PriorityQueue::~PriorityQueue()
{
std::cout << "\nDeconstructor called." << endl;
delete[] items.elements;
}
PriorityQueue PriorityQueue::operator=(const PriorityQueue &originalPQ)
{
//This function is started after the return value, the right operand, has been deconstructed.
std::cout << "\nAssignment called." << endl;
for (int i = 0; i < maxItems; i++)
items.elements[i] = originalPQ.items.elements[i];
return *this;
}
It is a little hard to tell exactly what the problem is without looking at how you are returning the PriorityQueue from your FindThroughPaths method, but it is likely that the problem is that you are missing a copy constructor in the PriorityQueue class.
PriorityQueue::PriorityQueue(const PriorityQueue &other)
{
std::cout << "\nCopy constructor was called" << endl;
// there are better ways to implement this, but I think this will correctly
// defer to the assignment operator you wrote
*this = other;
}
When you return an object from a method, the copy constructor is invoked to build the object that will be returned. If you have not implemented a copy constructor, then a default implementation is used, and that default will not be sufficient in your case.
The destructor will still be called to destroy the PriorityQueue object that is local to the FindThroughPaths method.
You might find this other question about returning an object from a method to be helpful.
I ran the following code
#include <iostream>
using namespace std;
class Count
{
private:
int count;
public:
//Constructor
Count():count(0) { cout << "Constructor called" << endl; }
//Destructor
~Count() { cout << "Destructor called" << endl; }
//Display the value.
Count display()
{
cout << "The value of count is " << count << endl;
return *this;
}
};
int main()
{
Count C;
C.display();
}
Result :-
Constructor called
The value of count is 0
Destructor called
Destructor called
In the above case, the destructor is called twice, one for destruction of the "this" object and one for return from main.
Is my observation correct ??
Can anyone explain me also the temporary object created in this process like why it is created, if created??
You are returning a copy from display() method thus it needs to be destructed too. So, in your main you actually have 2 objects, one - implicitly.
The destructor is called twice because your display function returns a copy of the Count instance that it is called on. So that gets destroyed along with your C instance within main.
2 instances = 2 destructor calls.
If you specify and implement your function to return an instance of Count then it will do so. If you don't want this behaviour, then change the return type to void and don't return anything - then your code will contain just the one instance C.
Your code here
Count display() {
// ^^^^^
cout << "The value of count is " << count << endl;
return *this; // <<<<<<
}
creates an implicit copy of your instance that is returned and immediately destroyed, hence the second destructor call.
Yes correct.
Your function display() created a copy which made a second object.
if you return a reference you wouldn't get the copy.
Count& display() { return *this; }
I have a few lines of code and I don't get, why and where the copy constructor is called. Could you explain it to me?
The output is:
CS10
CS99
CC100
Obj10=Obj100
D100
Obj10=Obj99
D99
D10
This is my source code:
#include <iostream>
using namespace std;
class my
{
int m;
public:
my(int i): m(i)
{
cout << "CS" << m << endl;
}
my(const my& c): m(c.m+1)
{
cout << "CC" << m << endl;
}
~my()
{
cout << "D" << m << endl;
}
my& operator=(const my &c)
{
cout << "Obj" << m << "=Obj" << c.m << endl;
return *this;
}
};
my f(my* x)
{
return *x;
}
int main()
{
my m1(10);
my m2(99);
m1 = f(&m2); // creates a new object
m1 = m2; // does not create a new object
}
Why and where is copy constructor called causing the output CC100 and D100?
In this function
my f(my* x)
{
return *x;
}
called in statement
m1 = f(&m2); // creates a new object
the copy constructor is called to copy object *x in the return temporary object.
In fact it looks as
my tmp = *x; // the copy constructor is called
m1 = tmp;
When trying to think about when a copy constructor is called you should keep a few things in mind:
Scope - functions can't see outside of themselves and their associated namespace. If you want to pass a variable to a function you need to save it in the global environment, repush a scoped copy and then operate on it.
When you use passing by reference you operate on the global copy but since in this case you are returning the value that is pointed to and not a pointer you have to push that return value onto the stack separately because it is stored at a different temporary register address that is popped off the stack after you assign it to a permanent location in main. That's where the destructor comes in.
You made a temporary return value to pass the value out of your function so it's got to be deleted because L1, L2, and L3 cache are all prime real estate.
I highly recommend doing a little bit of reading on assembly code operations or even try compiling simple programs into assembly and seeing how the low level languages work under the hood. Cheers!
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
No call to the copy constructor
In this code copy constructor is never called (neither does move constructor, or assignment operator). How it is possible? Can someone explain how function returns values, what happens with stack and registers (or post some good link)?
#include <iostream>
#include <cstring>
using namespace std;
class Test;
Test getnew(int arg);
class Test
{
public:
char *conts;
int len;
Test(char* input = NULL){conts = new char[len=10];
if(input)strncpy(conts,input,9);else strcpy(conts,"xxxxx");
cout << "\nconstructor: " << conts;
};
Test(const Test& t){
conts = new char[10];
if(t.len)strncpy(conts,t.conts,9);
len = t.len;
cout << "\ncopy-constructor: " << conts;
};
Test(Test&& t){
conts = t.conts;
t.conts = NULL;
std::swap(len,t.len);
cout << "\nmove-constructor: " << conts;
};
~Test(){
cout << "\ndestructor";
if(conts)delete [] conts;
len = 0;
conts = NULL;
};
Test& operator=(Test rhs)
{
std::swap(conts,rhs.conts);
std::swap(len,rhs.len);
cout << "\nassigend: " << conts;
}
};
int main()
{
Test t2 = getnew(1);
cout << endl << t2.conts;
return 0;
}
Test getnew(int arg)
{
Test retj("FFFFF");
return retj;
}
Only one constructor and one destructor is called. But object t2 has value member conts initialized with correct value "FFFF". I know that return value optimizations are applied, but how object t2 is initialized?
In theory, what should happen is that the compiler creates a temporary copy of your return value and that temporary object is then assigned to the variable which receives the output of the function.
However, the compiler is allowed to elide copies and moves of a returned value even though the copy constructor or move constructor has side-effects. In your case, this turns into a so-called NRVO (Named Return Value Optimization), which is a special case of RVO (Return Value Optimization).
Thus, it is very likely that what you are seeing is a result of a move elision. There are compiler options to disable this optimization, but some compilers (e.g. Clang 3.2) have bugs handling those options (see the answer to this question).
Using return value optimization, T2 is assigned to the Test object initialized in getnew. That's how RVO works.
I am trying to call the constructor H, but for some reason its not being called.
I get no error when I compile my code, and I get the output:
A object initialized.
H object initialized.
If H was initialized properly, the cout from the constructor should also be shown.
Can someone please help? Thank you.
I also have another question. How can I change the value of hVec[i].a and have the value of
aArray[i].a take upon this value as well? I know I am suppose to use pointers, but an very confused. Sorry for all the questions; I'm reltaively new to programming in C++.
#include <vector>
#include <iostream>
struct A
{
A(int av):a(av){}
int a;
};
struct Heap
{
Heap(std::vector<A> hVal)
{
std::cout << "Constructor for H object. \n";
for (int i=0; i<hVal.size(); ++i)
{
hVec.push_back(hVal[i]);
std::cout << "hVec[i].a = " << hVec[i].a << " ";
}
std::cout << std::endl;
}
std::vector<A> hVec;
};
int main()
{
A a0(2), a1(4), a2(8);
std::vector<A> aArray;
aArray.push_back(a0);
aArray.push_back(a1);
aArray.push_back(a2);
std::cout << "A object initialized. \n";
Heap h(A);
std::cout << "H object initialized. \n";
return 0;
}
Your struct Heap does not have a constructor which takes A as argument.
However, you can initialize h with aArray which is std::vector<A> type
Heap h(aArray);
In C++, unless you are trying to be compatible with C, otherwise just use class instead of struct
Heap h(A);
This declares a function of type Heap(A) named h. Perhaps you meant:
Heap h(aArray);
This declares a local variable of type Heap named h.
use Heap h(aArray); instead of Heap h(A);
The line Heap h(A); declares a function h taking an object of type A as parameter, and returns an object Heap.