As far as I know you call the copy constructor in the following cases:
1 When instantiating one object and initializing it with values from another object
2 When passing an object by value.
3 When an object is returned from a function by value.
I decided to put this to the test and I made this small program testing this (with messages each time a constructor is called. It seems to work for the first two cases, but not for the third one. I want to find out my mistake. Ideas are welcomed.
#include <iostream>
using namespace std;
class Circle{
private:
double* data;
public:
Circle();
Circle(double* set);
Circle(const Circle& tt1);
~Circle();
Circle& operator=(const Circle& tt1);
};
Circle :: Circle()
{
cout << "Default constructor called" << endl;
data = NULL;
}
Circle :: Circle(double* set)
{
cout << "Set up constructor called" << endl;
data = new double[3];
copy(set, set+3, data);
}
Circle :: Circle(const Circle& tt1)
{
cout << "Copy constructor called" << endl;
data = new double[3];
copy(tt1.data, tt1.data+3, this->data);
}
Circle :: ~Circle()
{
cout << "Destructor called!" << endl;
delete[] data;
}
Circle& Circle :: operator=(const Circle& tt1)
{
cout << "Overloaded = called" << endl;
if(this != &tt1)
{
delete[] this->data;
this->data = new double[3];
copy(tt1.data, tt1.data+3, this->data);
}
return *this;
}
void test2(Circle a)
{
}
Circle test3()
{
double arr [] = { 3, 5, 8, 2};
Circle asd(arr);
cout<< "end of test 3 function" << endl;
return asd;
}
int main()
{
cout <<"-------------Test for initialization" << endl;
double arr [] = { 16, 2, 7};
Circle z(arr);
Circle y = z;
cout << "-------------Test for pass by value" << endl;
test2(z);
cout <<"------------- Test for return value-------"<<endl;
Circle work = test3();
cout<< "-----------Relese allocated data" << endl;
return 0;
}
Because of Return Value Optimization the 3rd test case's copy constructor call is optimized away by the compiler.
In virtually all cases, the compiler is not allowed to change the meaning of your code. It can (and will when optimising) change your code dramatically from what you wrote into something more optimal whilst never changing the observable behaviour of your code.
This is why when debugging you'll see many confusing things as the generated code does something totally different from what you wrote whilst keeping the observable state intact. This actually makes writing debuggers hard - if for instance you want to examine the value of a variable whilst debugging, the compiler may've decided that the variable didn't even need to exist and so in that case what should the debugger show?
In a very small number of cases the compiler is allowed to change the meaning of your code. The RVO and NRVO [same link as above] are two examples of these - the compiler is allowed to elide the copy constructor in these limited cases - which is what you are seeing. The compiler should still check that your copy constructor exists and is accessible - for instance it isn't private, deleted or impossible to generate - but it can then not use it.
For this reason Copy Constructors [and by inference destructors] should just do the normal thing - as if they're elided you'll get observably different behaviour.
Related
This question already has answers here:
How to enforce move semantics when a vector grows?
(3 answers)
Closed 3 years ago.
First, I am not good at English, so I use a translator.
This code is the code that supports move semantic in vector.
A code that creates a single vector and inserts a Test object into the push_back() method.
The result of this code is that every time a Test object is added because of a push_back() method, the move constructor should be called, right?
But the compiler calls the move constructor only when new objects are inserted, and the old ones call the copy constructor.
Why is this happening? Am I missing something?
#include <iostream>
#include <vector>
using namespace std;
class Test
{
public:
Test(int data1, int data2) :data1(data1), data2(data2)
{
cout << "Normal Constructor" << endl;
}
Test(const Test& src)
{
cout << "Copy Constructor" << endl;
this->data1 = src.data1;
this->data2 = src.data2;
}
Test(Test&& rhs)
{
cout << "Move Constructor" << endl;
this->data1 = rhs.data1;
this->data2 = rhs.data2;
rhs.data1 = 0;
rhs.data2 = 0;
}
Test& operator=(const Test& src)
{
if (this == &src)
return *this;
cout << "Copy assignment operator" << endl;
this->data1 = src.data1;
this->data2 = src.data2;
return *this;
}
Test& operator=(Test&& rhs)
{
if (this == &rhs)
return *this;
cout << "Move assignment operator" << endl;
this->data1 = rhs.data1;
this->data2 = rhs.data2;
rhs.data1 = 0;
rhs.data2 = 0;
return *this;
}
private:
int data1, data2;
};
int main()
{
vector<Test> vec;
for (int i = 0; i < 5; i++)
{
cout << "Iteration " << i << endl;
vec.push_back(Test(100, 100));
cout << endl;
}
}
The reason std::vector chooses the copy constructor instead of the move constructor is that your move constructor isn't nothrow. Why does std::vector care?
Well, std::vector has some exception safety guarantees. See, for example, std::vector::push_backs exception guarantee:
If an exception is thrown (which can be due to Allocator::allocate() or element copy/move constructor/assignment), this function has no effect (strong exception guarantee).
This means that when a exception is thrown somehow, it doesn't blow up the whole container, and in this case a strong exception guarantee even guarantees you that a bad insertion has no impact at all on the vector.
Having a non-noexcept move constructor is a problem, because if a move would throw on reallocation, std::vector could not go back to a valid state as it might have already moved half of its items over but not the other half, and trying to move them back to the old memory location might throw as well. Copying doesn't have this problem as the old items stay intact, so if a copy would throw, std::vector just needs to destruct all (new) items it has copied so far and give up. You, as a user of the collection, have the guarantee that a bad insertion or reallocation leaves all other items intact. This is why it will only use the move-constructor if it is guaranteed the move can never throw, which is promised by noexcept.
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 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!
I have a below code. Every time Constructor is called, I increase a counter and the counter is decreased every time Destructor is called. After instantiating three class objects, I tried printing out the counter value. Then I tried printing out the counter value again after deleting one of the objects. The expected values were 4 and 3, but instead I get 2 and 1.
I actually tried printing out something within the Constructor and Destructor to observe how many times they were actually called, but surprisingly Destructor was called several times in addition to the time when I called "delete object". Is it because the Destructor is called automatically? If so, is there any way to turn the feature off to test my code?
** The code originally has Add and Mult functions in the class, but I omitted here because the details of the functions seem irrelevant here.
#include <iostream>
using namespace std;
class Complex{
private:
double x, y;
static int count;
Complex Add(Complex como)
{
Complex t;
t.x=x+como.x;
t.y=y+como.y;
return t;
}
Complex Mul(Complex como)
{
Complex t;
t.x=(x*como.x)-(y*como.y);
t.y=(y*como.x)+(x*como.y);
return t;
}
public:
Complex(double a=0, double b=0) : x(a), y(b) {count++;}
~Complex() {count--;}
void Print() {cout << "(" << x << ", " << y << ")" << endl;}
static int GetCount() {return count;}
};
int Complex::count=0;
int main()
{
Complex com1(1.0, 2.0), com2(3.0, 4.0);
Complex com3;
com1.Print(); cout << endl;
com2.Print(); cout << endl;
com3 = com1.Add(com2); com3.Print(); cout << endl;
Complex *pcom4 = new Complex;
*pcom4 = com1.Mul(com2); pcom4->Print(); cout << endl;
cout << "#complex numbers = " << com1.GetCount() << endl;
delete pcom4;
cout << "#complex numbers = " << com1.GetCount() << endl;
return 0;
}
In C++ you can construct objects in three ways:
using the "constructor"
using the "copy constructor"
using the "move constructor"
If don't define them the compiler will automatically write the code for you (unless you stop it from doing that explicitly).
Your method Mul and Add are accepting the other complex number by value and this means that a copy constructor call will be used to copy the argument of the call.
The automatic synthesized copy constructor doesn't increment the counter.
Your methods are taking Complex objects as parameters (not references to existing objects), so new objects are being created for each call and are destroyed at the end of the call.
when I compile the following code:
#include <cstdio>
char retChar(){
return 'c';
}
int main(){
retChar() = 'f';
}
I got the following errors:
modify.cpp: In function ‘int main()’:
modify.cpp:8:14: error: lvalue required as left operand of assignment
I have searched similar questions to this error, but the answers just seem to be situation specific. And I didn't find the answer to my question yet.(maybe somewhere else?)
=======================================add=======================================
but in the situation below:
#include <iostream>
class int_Bag{
int a;
int b;
public:
int_Bag(const int x, const int y);
int_Bag(const int_Bag&c);
int_Bag& operator =(const int_Bag &c){
std::cout<< "copy assignment constructor called\n";
a = c.a;
b = c.b;
return *this;
}
~int_Bag();
void debug();
};
int_Bag::int_Bag(const int x, const int y):a(x),b(y){}
int_Bag::~int_Bag(){
std::cout<< "destructor called\n";
}
int_Bag::int_Bag(const int_Bag&c):a(c.a),b(c.b){
std::cout<< "copy constructor called\n";
}
int_Bag getBag(const int_Bag &c){
return c;
}
void int_Bag::debug(){
std::cout << a <<"," << b << std::endl;
}
int main(){
int_Bag *bag1 = new int_Bag(3,4);
int_Bag *bag2 = new int_Bag(5,6);
std::cout<< "assignment expression begins\n";
getBag(*bag1) = *bag2;
bag1->debug();
delete bag1;
delete bag2;
}
this program just compile and run well:
assignment expression begins
copy constructor called
copy assignment constructor called
destructor called
3,4
destructor called
destructor called
We can see from the results that, when getBag() is being executing, a temporary object is created by calling copy constructor. So I think for the first situation, that assignment doesn't work is not simply due to the fact that the returned char is temporary.
Why assignment getBag(*bag1) = *bag2;works here?
What is the difference between these two situations for assignment expression?
I suppose that, for the second situation, the whole assignment expression is divided into two steps: first to call getBag() then second the copy assignment is called to copy *bag2 to the newly created temporary object returned by getBag(). However, in first situation, retChar() returns a rvalue(also temporary) which can only appear on the RHS of an assignment as #Jonathan Leffler said.
The first situation stands alone just seems to be stupid question maybe(I see those negative remarks). Those questions I just added are actually what I am really confused about.
Looking forward to receiving comments on my supposal and other anwsers.
(from a c++ beginner ^^)
You are attempting to modify a temporary (an rvalue). That is not possible.
You can accomplish your goal in a few ways, but the best one likely is this:
int main()
{
char c = retChar();
c = 'f';
// ...
return 0;
}
You refer to code that has getObject() = something. That code is likely written in some form that is similar to this:
char& getChar()
{
static char c = 'c';
return c;
}
int main()
{
getChar() = 'f';
// ...
return 0;
}
This returns a reference (not a temporary). When you assign it to 'f', the value of the c variable in getChar becomes 'f'.
Original question
You can't assign to the result of a function like that. The function returns an r-value, something that can only appear on the RHS of an assignment. Contrast with an l-value which is something that can be assigned to.
If you really wanted to (you probably don't, though) you could write:
char *retChar(){
static char c = 'c';
return &c;
}
int main(){
*retChar() = 'f';
}
And now you've modified the variable inside the function retChar().
Amended question
This code does a more thorough job instrumenting your example:
#include <iostream>
class int_Bag
{
int a;
int b;
public:
int_Bag(const int x, const int y);
int_Bag(const int_Bag&c);
int_Bag& operator =(const int_Bag &c){
std::cout<< "copy assignment constructor called:\nold";
this->debug();
std::cout << "new";
c.debug();
a = c.a;
b = c.b;
return *this;
}
~int_Bag();
void debug() const;
};
int_Bag::int_Bag(const int x, const int y) : a(x), b(y)
{
std::cout << "basic(" << x << "," << y << ")\n";
}
int_Bag::~int_Bag()
{
std::cout << "destructor called";
this->debug();
}
int_Bag::int_Bag(const int_Bag &c) : a(c.a), b(c.b)
{
std::cout << "copy constructor called";
this->debug();
}
int_Bag getBag(const int_Bag &c)
{
std::cout << "getBag returns";
c.debug();
return c;
}
void int_Bag::debug() const
{
std::cout << "(" << a << "," << b << ")" << std::endl;
}
int main()
{
int_Bag *bag1 = new int_Bag(3, 4);
int_Bag *bag2 = new int_Bag(5, 6);
std::cout << "assignment expression begins\n";
getBag(*bag1) = *bag2;
std::cout << "assignment expression ended\n";
bag1->debug();
delete bag1;
delete bag2;
}
When I run it, the output is:
basic(3,4)
basic(5,6)
assignment expression begins
getBag returns(3,4)
copy constructor called(3,4)
copy assignment constructor called:
old(3,4)
new(5,6)
destructor called(5,6)
assignment expression ended
(3,4)
destructor called(3,4)
destructor called(5,6)
The value 5,6 is assigned to the temporary created/returned by getBag(), but is then destroyed. None of that affects the original 3,4 value in *bag1. The (anonymous) object created by getBag() is usable until the end of the full expression it appears in, but not beyond, so the whole assignment is still very dubious.
I was compiling with G++ 4.8.2 on Mac OS X 10.9.1 Mavericks, or G++ 4.8.1 on Ubuntu 13.10, in both cases with the options:
g++ -O3 -g -std=c++11 -Wall -Wextra -Werror intbag.cpp -o intbag
There was not the slightest murmur from the compilers, nor was valgrind 3.8.1 in the slightest perturbed by the memory access patterns.
I think C++ gives you enough rope to shoot yourself in the foot, or some such mixed metaphor.
You're trying to assign a character to a function, which isn't allowed!
I'm not sure why you think this might be allowed, or why you want to do it...
retChar() is a function. Functions are not like variables; they cannot be assigned to values. Your retChar() function returns a char that you can use in your main method. For example you could do:
char myChar = retChar();
and myChar would then be equal to f.
If you are finding yourself confused with these concepts then try having a look at this and this.