Constructors copying other objects

Pages: 12
I have been looking at lecture notes from MIT to learn C++.
In specific: http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-096-introduction-to-c-january-iap-2011/lecture-notes/MIT6_096IAP11_lec06.pdf

In one of the slides there was this example code provided:
class Point {
public:
double x, y;
Point(double nx, double ny) {
x = nx; y = ny; cout << "2-parameter constructor" << endl;
}
Point(Point &o) {
x = o.x; y = o.y; cout << "custom copy constructor" << endl;
}
};
int main() {
Point q(1.0, 2.0); // 2-parameter constructor
Point r = q; // custom copy constructor
// r.x is 1, r.y is 2
}

Now when I first saw the signature "Point(Point &o)" I thought okay the way it would be invoked is in the following manner:

int main() {
Point q(1.0,2.0);
Point r(q);
}

So now my questions:
1) Will that way (ie. "Point r(q);") work? If not, why? Please explain.
2) Assuming "Point r(q)" will work, how is that equivalent to "r = q"? I don't understand the theory behind that code and what's happening. I'd appreciate an explanation.

Thank you!
1) Yes Point r(q) will work as well.
2) I'm sure someone can explain 2) alot better than me, so please do so :P

@Framework, what do you mean with 'if you do something stupid'? http://cplusplus.com/doc/tutorial/classes/ also refers to using the copy constructor as Class var (&Class)?

As it says in the Classes II tutorial:
As well as a class includes a default constructor and a copy constructor even if they are not declared, it also includes a default definition for the assignment operator (=) with the class itself as parameter. The behavior which is defined by default is to copy the whole content of the data members of the object passed as argument (the one at the right side of the sign) to the one at the left side.
Last edited on
closed account (zb0S216C)
1) Yes, it'll work, but only if you do something stupid. It's common to have a copy-constructor take a reference to a constant object, as it allows the calling class construct itself based on a temporary object.

2) That will call the copy-constructor, since it's equivalent to constructing the calling class based on another object of the same type.

Wazzak
Last edited on
@expor - your answer before with the example of an integer and how values are copied was did help a little so thank you

@Framework - sorry I didn't get your response.

Can you please break it down and provide a few more details. How is "Point r(q)" equivalent to "r = q"?

Thanks
closed account (zb0S216C)
RyanM wrote:
"Can you please break it down and provide a few more details. How is "Point r(q)" equivalent to "r = q"?"

Because r = q invokes the copy-constructor. q is passed to r, and r copies each member of q. It's equivalent to this: Point r(q). How much detail are you looking for?

Wazzak
2) This is only true if you use the assignment operator to assign a value during declaration. The compiler is allowed to optimize the assignment into a copy construction:

1
2
3
4
Point q(1.0f, 1.0f);
Point a = q; //Same as Point a(q).
Point b;
b = q; //This will invoke the assignment operator, and not the copy constructor. 


The copy constructor is usually faster, since the class can construct its members using the values of q, instead of constructing and then assigning the values of q.

1) Framework, I also don't understand what you mean by do something stupid? As I said about 2), Point a = q, and Point a(q) are identical. Or are you talking about readability?

EDIT: 255 posts :D So much more exciting than 1000. Maybe not 1024 though.
Last edited on
closed account (zb0S216C)
@BlackSheep: By "doing something stupid", I mean not doing any actual copying as the assignment, and copy-constructor should. For example:

1
2
3
4
5
6
7
8
9
10
11
12
struct F
{
    F(F const &AnF)
    {
        /* Copy nothing */ 
    }

    F &operator = (F const &AnF)
    {
        /* Copy nothing */
    }
};

The above code does something stupid: it doesn't copy anything. That's what I mean by "doing something stupid."

Wazzak
No, what Framework meant by
only if you do something stupid
, is that copy-constructors should take a reference toa constant, to avoid changing the object from which the data is copied. This also allows constructon form temporaries, which isn't possible with regular references.
@BlackSheep & @Framework, thanks guys that helps. That's a great explanation.

"It's common to have a copy-constructor take a reference to a constant object, as it allows the calling class construct itself based on a temporary object."


Do you mind explaining the use of a constant a little more please. Where, when, and how it is used. And how does this allow construction based on a temporary object.

Just a note, I only started learning c++ last week, so take it easy on me :P
OK, the copy constructor's purpose is to copy from ANY object, even a temporary, which can't be a regular reference because of an obvious reason: youcan't modify it! Temporarys are mostly, or maybe even only, literals and constructor results. They musn't be modified, because that would lead to unexpected results. Taking a CONSTANT reference allows correct code, and no undefined results. Another reson for taking a constant reference is not to accidentally modify the object you are copying, as it would mostly be unexpected.
Can you explain what a temporary is? Sorry.
Also what is a regular reference?
closed account (zb0S216C)
A temporary object/variable (yes, they are two different things) is an unnamed object/variable. Its lifetime depends on how you declare it. Consider these code fragments:

 
int const &X = 10;

Here, X is a reference to an constant int (read it backwards). The 10 you see is something you wouldn't expect. When the compiler sees this declaration, it creates an temporary, unnamed int const with the value of 10. The unnamed int is then bound to X. "Bound" means to assign something to a reference. What ever is assigned to the reference, or bound, is called a "referent". The reference has to be constant, because you're assigning a literal to it. The lifetime of the unnamed int is the same as the reference that its bound to; In this case, X.

 
int &X = /*...*/;

This is a regular reference. It cannot be assigned to anything that is constant, which means it cannot be bound to unnamed objects/variables like the above reference. The lifetime of the referent is independent of the reference, which means the reference can be destroyed before or after the referent's lifetime ends.

Wazzak
Last edited on

@RyanM (10)

Can you explain what a temporary is? Sorry.


Well, the expression

Point( 0, 0 );

creates a temporary object of type Point.

A temporary object can be binded to const reference.

You declared your copy constructor as

Point(Point &o);

Now consider the following declaration

Point p1( Point( 0, 0 ) );

This code shall not be compiled because inside the parentheses following name p1 there is a temporary object that shall be binded to const reference. If you would declare your copy constructor the following way

Point( const Point &o);

then the code above woudl be compiled.

Another example is when a constant object is used to initialized another object. For example

1
2
const Point p1( 0, 0 );
Point p2( p1 );


Again the code will not be compiled because your constructor does not accept a constant reference.
Last edited on
Also what is a regular reference?

A regular reference is a normal reference, just a reference, no const, volatile, static, extern.. just a refrence(as the name suggests, doh!)
Those were great answers, but they brought up a few more questions...

@Framework

int const &X = 10;

1) Why do you say it is unnamed? Isn't it named X? How do I know when something is named or it isn't?

The reference has to be constant, because you're assigning a literal to it.

2) Do you mind explaining what is a literal and when something is a literal.
3) Why does it have to be constant? (maybe I'll understand this when I understand what a literal is)

1
2
3
int &X = /*...*/;

This is a regular reference. It cannot be assigned to anything that is constant


4) Why? so if I have a const int y = 5, I couldn't do X = y?


@vlad from moscow

A temporary object can be bound to const reference.

1) Why can a temporary object be bound to a constant reference and not a regular reference? ie why do I have to make my constructor:
Point( const Point &o);

2) What is special about a constant reference or a constant variable for that matter? (I thought the only thing const did was say the value of this variable cannot be changed)

1
2
3
4
const Point p1( 0, 0 );
Point p2( p1 );

Again the code will not be compiled because your constructor does not accept a constant reference.


3) I don't get it! Can I not do the following:
1
2
3
const int y = 5;
int x;
x = y;

Because if I can do this shouldn't I be able to create an object based on a constant object? I mean what's so special about a constant or a temporary?


Thanks so much guys, I really appreciate you helping me out
1) No, he meant that the "10" is unnamed, not the variable it's stored in later.
2) a literal is a temporary described only by it's value. So these are literals:
true, '1', L'1', u8'1', u'1', U'1', "1", L"1", u8"1", u"1", U"1", R("1"), 1, 1u, 1l, 1ul, 1ll, 1ull, 1.0f, 1.0, 1.0L
but theese are not:
Point(1, 1), pair<int, int>(1, 1), vector<int>(2)
But they are all temporaries. Also every literal on which you use the literal("" _suffix(C++11)) operator are also literals.
To sum up, every literal is a temporary but not every temporary is a literal.
3) because, when you change the reference, you change the object it's reffering to. If the object it's reffering to is a constant, it musn't be changed, so common sense tells us you can't have a writable reference to a const object.
1) Because changing the value the temorary is reffering to would cause weird effects. Imagin there was no such rula and that could be done. Imagine what this code would do:
1
2
bool& mytrue=true;
mytrue=false;

It might actualy cange the value of the literal true to false!!
2) Yes the only thing const does is say it's value can't change, BUT it also means a lot of stuff HAVE to be const to accept const parameters, especially reference, because of the reason I stated in 1).
3) Yes, you can do that!
Last edited on
1. thx
2. got it :)
3. I think I get it...basically you are saying that if I say int &x = /*some constant such as 10*/ that means x is a reference to a constant in this case 10. Which means if I change x, the value of the constant (or in this case the literal "10" will change. So we have to make x an constant if it is a reference to a constant to maintain "constant-ness" :P

Did I get it?

1. I'm not following...
Point( const Point &o);

Here are my thoughts: when I say Point p1(Point(0,0)), Point(0,0) is a temporary object which means that it will be destroyed after the constructor is finished. The copy constructor by default doesn't copy the values from the temporary object to p1, but points to the temporary object instead. This is a problem because like I said the temporary object will be destroyed. Am I correct so far? Well how does adding const suddenly solve all that? The object is still temporary.

Also, the following code will work, correct?
1
2
Point p1( 0, 0 );
Point p2( p1 );


2. thx
3. thx
3. You got it ;)
1.
The copy constructor by default doesn't copy the values from the temporary object to p1, but points to the temporary object instead

What? By default, it makes a bit-wise copy from the object you are copying from , to *this.
This is a problem because like I said the temporary object will be destroyed

Not a problem at all, since you just make the 2 objects the same, you don't bind them with references and/or pointers!
Am I correct so far?

Nope!
Well how does adding const suddenly solve all that? The object is still temporary.

Yes, but adding const means that you can't change it, which means that the temporary, possibly a literal, still contains the same value! Also this guarranties that it is nothing but a COPY! That means you can't accidentally chang the object you are copying from, because then when you would use it's value later, you would wonder and wornder how the heck did it's value change, if you did NOTHIGN to change it in the main(). It would be really hard to debug it when it's inside the copy-constructor. Adding const assures you it won't happen.
Also, the following code will work, correct?
1
2
Point p1( 0, 0 );
Point p2( p1 );


yup.
Last edited on
The Class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Point {
public:
double x, y;

Point(double nx, double ny) {
x = nx; y = ny; cout << "2-parameter constructor" << endl;
}

/*
--REMOVE CUSTOM COPY CONSTRUCTOR--
Point(Point &o) {
x = o.x; y = o.y; cout << "custom copy constructor" << endl;
}
*/

};


The Main:
1
2
3
int main() {
Point p1( Point(0,0) ); // custom copy constructor
}


Statement 1 - Point(0,0) is a temporary object which will be destroyed after line 2 finishes being executed
Question 1 - on line 2, will p1 point to the temporary object or will it be located on the stack as it's own data?
Question 2 - If p1 is a distinct copy in memory then it shouldn't matter if we use const or not because it has no relationship to the temporary object any more. Right?
Question 3 - If however p1 does point to the temporary object, okay so then by making it a const does that mean despite it being temporary it won't be destroyed? But then it is not temporary! I'M CONFUSED!

Thanks for your help thought, seriously greatly appreciated.
Last edited on
1: It's it's own data! It's simple copy-schematics: type name(objectOfType_type); means:
a) name's binary representation is the same as the one of objectOfType_type
b) objectOfType_type's data is guarranteed to stay the same as before the constructor call
2: Uhh I hate repeating myself...
Viliml wrote:
copy-constructors should take a reference toa constant, to avoid changing the object from which the data is copied. This also allows constructon form temporaries, which isn't possible with regular references.
Viliml also wrote:
can't be a regular reference because of an obvious reason: youcan't modify it! Temporarys are mostly, or maybe even only, literals and constructor results. They musn't be modified, because that would lead to unexpected results. Taking a CONSTANT reference allows correct code, and no undefined results. Another reson for taking a constant reference is not to accidentally modify the object you are copying, as it would mostly be unexpected.
Viliml also wrote:
because, when you change the reference, you change the object it's reffering to. If the object it's reffering to is a constant, it musn't be changed, so common sense tells us you can't have a writable reference to a const object.
Viliml ALSO wrote:
adding const means that you can't change it, which means that the temporary, possibly a literal, still contains the same value! Also this guarranties that it is nothing but a COPY! That means you can't accidentally chang the object you are copying from, because then when you would use it's value later, you would wonder and wornder how the heck did it's value change, if you did NOTHIGN to change it in the main(). It would be really hard to debug it when it's inside the copy-constructor. Adding const assures you it won't happen.

3: It doen't POINT to the temporary because it's not a pointer, and it's this pointer doen't point to it either.! The only relation to the temporary is the data!
Pages: 12