writing `operator=` for non-static reference member class - c++

#include <iostream>
class Bar
{
protected:
public:
int & x;
Bar(int & new_x)
:x(new_x)
{}
Bar & operator = (const Bar toCopy)
{
x = toCopy.x;
return *this;
}
};
int main()
{
int x1(1);
int x2(2);
Bar bar = Bar(x1);
std::cout << bar.x << std::endl;
bar = Bar(x2);
std::cout << bar.x << std::endl;
bar.x = 5;
std::cout << bar.x << std::endl;
std::cout << x1 << std::endl;
std::cout << x2 << std::endl;
}
The output is:
1
2
5
5
2
What I am trying to do is copy x and save it within the object bar.
The output suggests to me that the assignment operator has not done its magic, both in terms of copying and taking the value of the new object. I have followed this link.
Changing x into a value rather than a reference is not possible, as in the real program x is an abstract class.
Please if possible abstain from using heap assignment.
EDIT:
1. I realized that I have just butchered the C++ language. I would like to apologize to all "C++ian" speaking computers. My motivation was to assign a member abstract variable on the stack. As far as I understand, it cannot be done on the stack, because the size of the derived class is not known at compile time.
2. OK... I am a total n00b...(no sh*t, Sherlock!). "Effective C++ programming" #rhalbersma is a must have. It contains essentials, yet you wont find them anywhere (copy constructions, copy initializer),.. in one place anyway.

References can be confusing. So can const pointers. I'll try to clear things up by talking about both of them at the same time. What can I say, I'm an optimist.
First, const pointers.
We'll start with a class called Foo. We can have a pointer to this class -- a Foo*. We can have a pointer to a const instance of this class -- a Foo const*. And we can have a const pointer to a non-const instance of this class -- a Foo*const.
A Foo const* is a pointer you can change to data you cannot change.
A Foo*const is a pointer you cannot change to data you can change.
I'll assume you got that. I am, after all, an optimist. Next, lets look at references.
While it is true that references are aliases, sometimes it helps to think about them in a world where things have concrete implementations in terms of other types.
A Foo& is analogous to a Foo*const -- a non-changeable "pointer" to an instance of Foo you can change. So the Foo you are talking about is always the same one, but you can change its state.
Now, it is a bit more than that. There is some syntactic sugar. When you create a reference to another variable, it does the & automatically -- so when you do a Foo& f = a;, this is analogous to Foo*const f = &a;.
Second, when you use ., it does the same as -> in the pointer case. (And similarly for (most?) other operators)
Third, when you do assignment, it clearly cannot change the pointer's value -- because it is const -- but instead it changes the value of the thing pointed to. So Foo& f = a; a = b; does the equivalent of Foo*const f = &a; *f = b;.
It assigns the thing pointed to, rather than the pointer, when you use operator=. But when you initialize it, it doesn't use operator=, even if you have a = token.
Initialization is not the same as assignment in general, and the semantics of what happens with a & reference and a * pointer in initialization and assignment are very different.
Foo& f = a; f = b; does two completely different things. Initialization of a reference initializes the "const pointer" portion -- assignment to a reference modifies the thing pointed to.
My personal name for how initialization and assignment mean different things with references is "reference semantics", as opposed to "pointer semantics" where both initialization and assignment change what thing is being pointed to. In "reference semantics", initialization picks what thing is being pointed to, and assignment changes the state of the thing that is pointed to.
This is highly confusing, and I hope I helped make it confusing in a different way.

Bar bar = Bar(x1); is not assignment, but copy-initialization. It calls the copy constructor, not the copy assignment operator.
The problem though is that you don't understand reference - the member Bar::x is just an alias for another variable. Assigning something to it will also modify the original one.

The x inside bar is the same variable as the one called "x1" in main.
That's what references do - they take a variable and give it another name that you can use to refer to it.
Whatever you do to that variable under this new name is the same as doing it under any other name.
First, after
Bar bar = Bar(x1);
(which is copy initialization, not assignment)
"bar.x" refers to the same variable as the "x" inside the anonymous object on the right hand side, which in turn is a different name for "x1" in main.
After this, the name "bar.x" refers to the same variable as the name "x1".
The line
bar = Bar(x2);
assigns the value (i.e., 2) of the anonymous object's x, which is the same variable as x2, to the variable that is called "x" inside bar, but whose name is "x1" in main.
The line
bar.x = 5;
then assigns the value 5 to the variable whose name is "bar.x" which, again, is the same variable as "x1" in main.
You cannot make it refer to a different variable.
If you want something that can refer to different variables, you must use a pointer.

Related

What exactly is a const variable?

I understand const pointers. However I don't entirely understand const normal variables.
const int a
The statement above I understand because it's a primitive. So it can only mean one thing: the value of a cannot be changed.
But whag about this one?
const Car car
This could mean one of two things:
A- The value of variable car can't be changed. I.e., I can't put inside it a different Car.
B- The object itself that this variable holds cannot be changed. I.e., we can't change the state of the object that's inside this variable.
Which one of these is correct?
Both.
Since The value of variable car and the state of the object that's inside this variable are the same thing.
An objects is nothing more than the aggregation of its members.
Both are correct:
A- The value of variable car can't be changed. I.e., I can't put inside it a different Car.
you will not be able to assign to car any other Car class instances. If you are using java, then this is not the same as assigning reference to new variable, in c++ whole object is copied in this case.
B- The object itself that this variable holds cannot be changed. I.e., we can't change the state of the object that's inside this variable.
its correct because you will only be able to call const methods which are also not allowed to modify fields, unless they are marked as mutable.
This isn't an entirely straightforward question. Specifically, making car const makes the compiler treat all of car's non-mutable members as const. It also prevents you from calling non-const member functions on car.
What does treating a member as const mean? Well, it depends on its type. If it's a pointer, it's the pointer and not the pointee that is treated as const. Say we have the following class:
class C
{
public:
Foo foo;
Bar *bar;
mutable Baz baz;
void nc()
{
foo = ...; // fine
bar = ...; // fine
*bar = ...; // fine
baz = ...; // fine
}
void c() const
{
foo = ...; // not fine
bar = ...; // not fine
*bar = ...; // fine
baz = ...; // fine
}
};
const C c;
c.foo = ...; // not fine
c.bar = ...; // not fine
*c.bar = ...; // fine
c.baz = ...; // fine
c.nc(); // not fine
c.c(); // fine
If you had a const instance of C, you would be able to call const member functions on it. You (depending on access) or those const member functions would also be able to change the thing pointed to by bar and the actual object baz, but not foo or bar, since the compiler would treat foo as being of type const Foo, bar as being of type Bar *const and baz as being of type Baz.
To directly address your question, both A and B are roughly correct views of what's going on, but neither captures the true situation well enough to be an answer to the question.
In particular, A (which essentially says you can't assign to const objects) is a simplification, since it's possible (maybe unwise, but possible) to write an assignment operator that only assigns to mutable members or to pointees.
B is a simplification because it doesn't take into account the possible presence of mutable members inside your class. Depending on what you mean by 'state', it's closer to the truth, since mutable members are often used as part of the private implementation and don't represent part of the class's logical state, but it's still not really accurate.
Both are true. Assigning a new Car to car is done by invoking Car::operator=(Car const& other), whether explicitly implemented or compiler-generated. That, in turn, assigns all of the members of car from those of other. So assignment is state-changing.
From the confusion, I wonder if you're more used to a language like C# or Java which has reference-typed object variables instead of object-typed variables. There (like with pointers in C++), assigning to a variable is different from changing its state, because the original Car stored in car would still be out there somewhere, unchanged. But with value-typed object variables, you're not really putting "a different Car inside it" -- you're changing the original Car so that it looks the same as the new Car.

why use a const non-reference when const reference lifetime is the length of the current scope

So in c++ if you assign the return value of a function to a const reference then the lifetime of that return value will be the scope of that reference. E.g.
MyClass GetMyClass()
{
return MyClass("some constructor");
}
void OtherFunction()
{
const MyClass& myClass = GetMyClass(); // lifetime of return value is until the end
// of scope due to magic const reference
doStuff(myClass);
doMoreStuff(myClass);
}//myClass is destructed
So it seems that wherever you would normally assign the return value from a function to a const object you could instead assign to a const reference. Is there ever a case in a function where you would want to not use a reference in the assignment and instead use a object? Why would you ever want to write the line:
const MyClass myClass = GetMyClass();
Edit: my question has confused a couple people so I have added a definition of the GetMyClass function
Edit 2: please don't try and answer the question if you haven't read this:
http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
If the function returns an object (rather than a reference), making a copy in the calling function is necessary [although optimisation steps may be taken that means that the object is written directly into the resulting storage where the copy would end up, according to the "as-if" principle].
In the sample code const MyClass myClass = GetMyClass(); this "copy" object is named myclass, rather than a temporary object that exists, but isn't named (or visible unless you look at the machine-code). In other words, whether you declare a variable for it, or not, there will be a MyClass object inside the function calling GetMyClass - it's just a matter of whether you make it visible or not.
Edit2:
The const reference solution will appear similar (not identical, and this really just written to explain what I mean, you can't actually do this):
MyClass __noname__ = GetMyClass();
const MyClass &myclass = __noname__;
It's just that the compiler generates the __noname__ variable behind the scenes, without actually telling you about it.
By making a const MyClass myclass the object is made visible and it's clear what is going on (and that the GetMyClass is returning a COPY of an object, not a reference to some already existing object).
On the other hand, if GetMyClass does indeed return a reference, then it is certainly the correct thing to do.
IN some compilers, using a reference may even add an extra memory read when the object is being used, since the reference "is a pointer" [yes, I know, the standard doesn't say that, but please before complaining, do me a favour and show me a compiler that DOESN'T implement references as pointers with extra sugar to make them taste sweeter], so to use a reference, the compiler should read the reference value (the pointer to the object) and then read the value inside the object from that pointer. In the case of the non-reference, the object itself is "known" to the compiler as a direct object, not a reference, saving that extra read. Sure, most compilers will optimise such an extra reference away MOST of the time, but it can't always do that.
One reason would be that the reference may confuse other readers of your code. Not everybody is aware of the fact that the lifetime of the object is extended to the scope of the reference.
The semantics of:
MyClass const& var = GetMyClass();
and
MyClass const var = GetMyClass();
are very different. Generally speaking, you would only use the
first when the function itself returns a reference (and is
required to return a reference by its very semantics). And you
know that you need to pay attention to the lifetime of the
object (which is not under your control). You use the second
when you want to own (a copy of) the object. Using the second
in this case is misleading, can lead to surprises (if the
function also returns a reference to an object which is
destructed earlier) and is probably slightly less efficient
(although in practice, I would expect both to generate exactly
the same code if GetMYClass returns by value).
Performance
As most current compilers elide copies (and moves), both version should have about the same efficiency:
const MyClass& rMyClass = GetMyClass();
const MyClass oMyClass = GetMyClass();
In the second case, either a copy or move is required semantically, but it can be elided per [class.copy]/31. A slight difference is that the first one works for non-copyable non-movable types.
It has been pointed out by Mats Petersson and James Kanze that accessing the reference might be slower for some compilers.
Lifetime
References should be valid during their entire scope just like objects with automatic storage are. This "should" of course is meant to be enforced by the programmer. So for the reader IMO there's no differences in the lifetimes implied by them. Although, if there was a bug, I'd probably look for dangling references (not trusting the original code / the lifetime claim for the reference).
In the case GetMyClass could ever be changed (reasonably) to return a reference, you'd have to make sure the lifetime of that object is sufficient, e.g.
SomeClass* p = /* ... */;
void some_function(const MyClass& a)
{
/* much code with many side-effects */
delete p;
a.do_something(); // oops!
}
const MyClass& r = p->get_reference();
some_function(r);
Ownership
A variable directly naming an object like const MyClass oMyClass; clearly states I own this object. Consider mutable members: if you change them later, it's not immediately clear to the reader that's ok (for all changes) if it has been declared as a reference.
Additionally, for a reference, it's not obvious that the object its referring to does not change. A const reference only implies that you won't change the object, not that nobody will change the object(*). A programmer would have to know that this reference is the only way of referring to that object, by looking up the definition of that variable.
(*) Disclaimer: try to avoid unapparent side effects
I don't understand what you want to achieve. The reason that T const& can be bound (on the stack) to a T (by value) which is returned from a function is to make it possible other function can take this temporary as an T const& argument. This prevents you from requirement to create overloads. But the returned value has to be constructed anyway.
But today (with C++11) you can use const auto myClass = GetMyClass();.
Edit:
As an excample of what can happen I will present something:
MyClass version_a();
MyClass const& version_b();
const MyClass var1 =version_a();
const MyClass var2 =version_b();
const MyClass var3&=version_a();
const MyClass var4&=version_b();
const auto var5 =version_a();
const auto var6 =version_b();
var1 is initialised with the result of version_a()
var2 is initialised with a copy of the object to which the reference returned by version_b() belongs
var3 holds a const reference to to the temoprary which is returned and extends its lifetime
var4 is initialised with the reference returned from version_b()
var5 same as var1
var6 same as var4
They are semanticall all different. var3 works for the reason I gave above. Only var5 and var6 store automatically what is returned.
there is a major implication regarding the destructor actually being called. Check Gotw88, Q3 and A3. I put everything in a small test program (Visual-C++, so forgive the stdafx.h)
// Gotw88.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
class A
{
protected:
bool m_destroyed;
public:
A() : m_destroyed(false) {}
~A()
{
if (!m_destroyed)
{
std::cout<<"A destroyed"<<std::endl;
m_destroyed=true;
}
}
};
class B : public A
{
public:
~B()
{
if (!m_destroyed)
{
std::cout<<"B destroyed"<<std::endl;
m_destroyed=true;
}
}
};
B CreateB()
{
return B();
}
int _tmain(int argc, _TCHAR* argv[])
{
std::cout<<"Reference"<<std::endl;
{
const A& tmpRef = CreateB();
}
std::cout<<"Value"<<std::endl;
{
A tmpVal = CreateB();
}
return 0;
}
The output of this little program is the following:
Reference
B destroyed
Value
B destroyed
A destroyed
Here a small explanation for the setup. B is derived from A, but both have no virtual destructor (I know this is a WTF, but here it's important). CreateB() returns B by value. Main now calls CreateB and first stores the result of this call in a const reference of type A. Then CreateB is called and the result is stored in a value of type A.
The result is interesting. First - if you store by reference, the correct destructor is called (B), if you store by value, the wrong one is called. Second - if you store in a reference, the destructor is called only once, this means there is only one object. By value results in 2 calls (to different destructors), which means there are 2 objects.
My advice - use the const reference. At least on Visual C++ it results in less copying. If you are unsure about your compiler, use and adapt this test program to check the compiler. How to adapt? Add copy / move constructor and copy-assignment operator.
I quickly added copy & assignment operators for class A & B
A(const A& rhs)
{
std::cout<<"A copy constructed"<<std::endl;
}
A& operator=(const A& rhs)
{
std::cout<<"A copy assigned"<<std::endl;
}
(same for B, just replace every capital A with B)
this results in the following output:
Reference
A constructed
B constructed
B destroyed
Value
A constructed
B constructed
A copy constructed
B destroyed
A destroyed
This confirms the results from above (please note, the A constructed results from B being constructed as B is derived from A and thus As constructor is called whenever Bs constructor is called).
Additional tests: Visual C++ accepts also the non-const reference with the same result (in this example) as the const reference. Additionally, if you use auto as type, the correct destructor is called (of course) and the return value optimization kicks in and in the end it's the same result as the const reference (but of course, auto has type B and not A).

[C ++ pass-by-value]: can the content of the original variables get modified by the called function?

I have always assumed that passing variables with [pass-by-value] in [c++], makes a copy of them, and so the function receiving these copies can not change the original variable's content.
I guess it is because when argument is passed by value, [copy-constructor] is called, and if it is not overridden by the programmer, the default [copy-constructor] does [shallow-copy] instead of [deep-copy]!
So my question is that why they called it pass-by-value, while in the case of having pointers in the class, the function has access to the reference of that pointer and can damage it. Also is this conclusion correct? "Whenever have pointers in the class, and you might pass an object of that class by value as a function argument, define the copy constructor!"
If this error is famous, does anyone know the name or phrase to this problem?
Below is my code that resulted in a modified list. Objects of this class contain an int member variable
as well as a pointer to a list of nodes member variable.
class ComplicatedObject{
public:
ComplicatedObject();
~ComplicatedObject();
//ComplicatedObject(const ComplicatedObject& c); // copy construtor
//ComplicatedObject& operator=(const ComplicatedObject& c); // =operator
int int_member_varialbe_; // an int member variable
void addToList(int d);
void printList();
private:
struct node{
int data;
node* next;
};
node* head_; // points to the beginning of a list (linkedlist of int)
};
The below code prints 2. And then prints 2 3 !
Test.cpp:
void myfunction(ComplicatedObject obj){
obj.addToList(3);
obj.int_member_variable_ = 5;
}
int main(void){
ComplicatedObject c_object;
c_object.addToList(2);
c_object.printList(); //prints 2
cout << "int member variable befor passing:";
cout << c-object.int_member_variable_ << endl; //prints 6 (a default value)
myfunction(c_object); //pass-by-value
cout << "int member variable after passing:";
cout << c-object.int_member_variable_ << endl; // prints 6 (not 5)
c_object.printList(); // prints 2 3 ! List get changed!
return 0;
}
You are correct. A shallow copy (which occurs if your class lacks a copy constructor) copies the pointers in your class, but not what they point to. You must define a copy constructor which performs a deep copy if you'd like to be able to properly pass a non-const object by value.
I have always assumed that passing variables with [pass-by-value] in
[c++], makes a copy of them, and so the function receiving these
copies can not change the original variable's content.
Yes, that's true.
I guess it is because when argument is passed by value,
[copy-constructor] is called, and if it is not overridden by the
programmer, the default [copy-constructor] does [shallow-copy] instead
of [deep-copy]!
A "copy" is a "shallow copy". A "copy" copies all the contents of the objects. And the contents are the fields. And if the field is a pointer, then the content is the pointer, the address. That's it.
So my question is that why they called it pass-by-value, while in the
case of having pointers in the class, the function has access to the
reference of that pointer and can damage it.
So? The things that those pointers point to are not part of the object. So it's irrelevant. The pointer is what's part of the object.
So my question is that why they called it pass-by-value, while in the case of having pointers in the class, the function has access to the reference of that pointer and can damage it.
Let's consider the following situation:
int func(int b, int* c)
{
/* some stuff */
}
for the first parameter, b, it is a "ByVal" delivery, so what the compiler usually does is
Create sizeof(int) space for b
Copy b to the space
The func can modify the local copy of b without affecting original b
This is necessary, since if it is automatically delivered "ByRef", compiler will meet trouble when non L-value is given, i.e. 1, as you cannot get the reference from a constant value.
Now let's see what happens to c. Again, it has a type of int*, not a int&, so it is treated the same way like int b.
However when c is a int* pointer, it does not store any other data except the address to some object with type int. So indirect access via the pointer is permitted and there is only copy of the address but not the value it points to,thus can be damaged.

dealing with assignment operator overloads; can you re-assign a reference?

If your class has a reference variable, then your overloaded assignment operator needs to be written.
I was under the impression that you could only set a reference once on instantiation and therefore cannot do something like:
MyClass& MyClass::operator=(const MyClass& rhs)
{
if (&rhs != this)
{
myReference = rhs.myReference;
}
return *this;
}
How do you solve this problem?
EDIT - OK so I'm told you cannot use an assignment operator on a class with a reference, fine. But then why does visual studio let me do it? The program runs and everything.
No, you cannot re-seat a reference.
Consider:
int a = 42, b = 43;
int &ar = a;
ar = b;
How can the compiler know that you are trying to reseat ar to refer to b, and not set the value of a to 43?
You solve this "problem" by using a pointer, not a reference.
EDIT: Per your edit,
OK so I'm told you cannot use an assignment operator on a class with a
reference, fine. But then why does visual studio let me do it? The
program runs and everything.
The premise of your conclusion is wrong. You can use an assignment operator on a class which contains a reference. What you cannot do is re-seat a reference. As demonstrated in my code above, if you try to reassign a reference using ar = a; you will not re-seat what ar refers to, but change the value of what ar refers to.
Visual Studio "lets you do it," without difficulty. The misunderstanding is exactly what Visual Studio is letting you do. It's not letting you re-seat the reference. It's letting you change the value of the referant. Here is an example that I hope will clarify what this means.
#include <iostream>
#include <string>
using namespace std;
class Foo
{
public:
void dump() const
{
cout << "Foo instance " << showbase << this << "\n";
}
};
class Bar
{
public:
Bar(Foo& foo) : foo_(foo) {}
Bar& operator=(const Bar& rhs)
{
foo_ = rhs.foo_;
return * this;
}
void dump() const
{
cout << showbase << "Bar instance " << this << "\t";
foo_.dump();
}
private:
Foo& foo_;
};
int main()
{
cout << "foo1: ";
Foo foo1;
foo1.dump();
cout << "foo2: ";
Foo foo2;
foo2.dump();
cout << "bar1 :";
Bar bar1(foo1);
bar1.dump();
cout << "bar2 :";
Bar bar2(foo2);
bar2.dump();
bar2 = bar1;
cout << "bar2 after assign :";
bar2.dump();
}
The code above establishes 2 Foo objects (foo1 and foo2) and creates 2 Bar objects, each of which has a reference to a different Foo. Bar has an operator=, which executes the following:
foo_ = rhs.foo_;
If C++ allowed you to re-seat references in this way, foo_ would now refer to a different instance of Foo. But, it doesn't. This doesn't change what foo_ refers to. Instead, it calls operator= on the Foo itself. Run the above code and you'll see that the address of the Foo in bar2 never changes. If you could re-seat references, it would change.
You can make an assignment operator with a class that uses a reference, but this line:
myReference = rhs.myReference;
Does not reassign the reference. If reassigns the thing that the reference is referring to. So, after that assignment, myReference and rhs.myReference do not now refer to the same object. But the things that they refer to now have equivalent values(or whatever assignment means for that type).
If you need a reassignable reference, use a pointer. That's what they're for. In fact, in modern C++, that's pretty much the only use left for a raw pointer. If the object you're referring to is dynamically allocated, then you should put it in a shared_ptr, and make myReference either another shared_ptr, or a weak_ptr.
In two words - you can't. References have semantics of an actual object, so assignment operator will actually call an assignment for underlying object and not the reference itself.
References can't be rebound. (Well, placement new can, but DON'T DO THAT!)
But the code is legal, even though it doesn't do what you think it does. It isn't rebinding or reassigning the reference, rather assigning to the referent (the target of the reference).
Your code works as written, however you are not reassigning the reference.
myReference = rhs.myReference;
Will assign the object referenced by rhs.myReference to myReference. Therefore assuming that before the assignment &myReference != &(rhs.myReference) was true, it will still be true after the assignment, however the objects at those addresses will contain the same values (so myReference == rhs.myReference if operator== is defined for the type and works in a lets say nonsuprising way). Reassigning the reference (which is impossible) would mean that after the assignment &myReference == &(rhs.myReference) would be true. So the real question is what you want to do: Do you want to copy the object referred by rhs.myReference into the one referred by this->myReference (in which case your code is fine), or do you want to make this->myReference refer to the same object as rhs.myReference (which is not possible with references, so you would need to use pointers).

why do we have to send the const " type " reference instead of just the types name to the constructor

i m trying to make a simple program ( & yes , it is a homework ) that can generate Dates , & like most of normal people : i made my Class attributes private , i tried to send the same type that i m working on to the constructor but the complier have not accept it , i did some research & i found out that in cases like that people generously send a const "type" reference to the constructor witch meant to me that have not understand OOP well
so why do we have to send the const " type " reference instead of just the types name to the constructor ? & please give me some links or websites for beginners
here is a peace of my Code :
class Date {
int d ;
int m ;
int y ;
public :
Date();
Date(int , int , int);
Date(const Date &);// my question is : why do we have to write this instead of Date( Date )
};
PS : sorry for my English
To paraphrase our question:
why do we have to write Date(const Date &) instead of Date(Date)?
I'm going to split this into two parts, the first answering why a copy constructor needs to take its argument per reference, the second why this needs to be a const reference.
The reason a copy constructor needs to take its argument per reference is that, for a function that's taking an argument per copy void f(T arg), when you call it f(obj), obj is copied into arg using T's copy constructor. So if you want to implement the copy constructor, you'd better not take the argument by copy, because this would call the copy constructor while invoking it, leading to an endless recursion. You can easily try this yourself:
struct tester {
tester(tester) {std::cout << "inside of erroneous copy ctor\n";}
};
int main()
{
tester t1;
std::cout << "about to call erroneous copy ctor\n";
tester t2(t1);
std::cout << "done with call erroneous copy ctor\n";
return 0;
}
That program should only ever write one line and then blow the stack.
Note: As Dennis points out in his comment, actually this program is not guaranteed to compile, so, depending on your compiler, you might not really be able to try it.
Bottom line: A copy constructor should take its argument by reference, because taking it per copy would require the copy constructor.
That leaves the question of why it is const T& and not simply T&? In fact, there are two reasons for that.
The logical reason is that, when you invoke the copy constructor, you do not expect the object copied from to change. In C++, if you want to express that something is immutable, you use const. This tells users that they can safely pass their precious objects to your copy constructor, because it won't do anything with it except read from it. As a nice side effect, if you implement the copy constructor and accidentally try to write to the object, the compiler throws an error message at you, reminding you of the promise made to the caller.
The other reason is that you cannot bind temporary objects to non-const references, you can only bind them to const references. A temporary object is, for example, what a function might return:
struct tester {
tester(tester& rhs) {std::cout << "inside of erroneous copy ctor\n";}
};
tester void f()
{
tester t;
return t;
}
When f() is called, a tester object is created inside, and a copy of it is then returned to the caller, which might then put it into another copy:
tester my_t = f(); // won't compile
The problem is that f() returns a temporary object, and in order to call the copy constructor, this temporary would need to bind to the rhs argument of tester's copy constructor, which is a non-const reference. But you cannot bind a temporary object to a non-const reference, so that code won't compile.
While you can work around this if you want (just don't copy the temporary, but bind it to a const reference instead, which extends the temporary's lifetime to the end of the reference's lifetime: const tester& my_t = f()), people expect to be able to copy temporaries of your type.
Bottom line: A copy constructor should take its argument by const reference, because otherwise users might not be willing or able to use it.
Here's one more fact: In the next C++ standard, you can overload functions for temporary objects, so-called rvalues. So you can have a special copy constructor that takes temporary objects overloading the "normal" copy constructor. If you have a compiler that already supports this new feature, you can try it out:
struct tester {
tester(const tester& rhs) { std::cout << "common copy ctor\n"; }
tester( tester&& rhs) { std::cout << "copy ctor for rvalues\n"; }
};
When you use the above code to invoke our f()
tester my_t = f();
the new copy constructor for rvalues should be called when the temporary object returned by the call to f() is copied to my_t and the regular copy constructor might be called in order to copy the t object from inside of f() to the returned temporary. (Note: you might have to disable your compiler's optimization in order to see this, as the compiler is allowed to optimize away all the copying.)
So what can you with this? Well, when you copy an rvalue, you know that the object copied from is going to be destroyed after the call to the copy constructor, so the copy constructor taking an rvalue (T&&) could just steal the values from the argument instead of copying them. Since the object is going to be destroyed anyway, nobody is going to notice.
For some classes (for example, for string classes), moving the value from one object to another could be much cheaper than copying them.
if I understood your question correctly, to avoid making copies/calling constructor of object.
void function(const T&); // does not create new T
void function(T&); // does not create newT, however T must be modifiable (lvalue)
void function(T); // creates new T
for simple types creating new copy is trivial (and often optimized away by compiler).
For complex object, creating new copy may be very expensive.
Hence you pass it by reference.
https://isocpp.org/wiki/faq/references
https://isocpp.org/wiki/faq/ctors
if you are asking why can not do the following:
struct type {
type(type);
};
Is because this would lead to infinite recursion, since constructor depends on itself
you can do this however
struct type {
type(type, int);
};
since this constructor is different from synthesized type(const type&)
http://en.wikipedia.org/wiki/Copy_constructor
In addition to #aaa's answer, I will try to answer the const part. The const part simply means that the object you are passing logically does not change. This makes sense, because when a copy constructor is called with a Date object argument d, d should not be modified at all!
You can remove the const and your code will still work the same way. However, const provides the additional security that you can never modify the variable marked as const. In your case, this means you can not call any of the non-const method of Date. This is enforced by the compiler at compile-time.
Historically this is the reason for introducing references to the language. Here's an explanation:
In C you can pass values to parameters by value (void f(struct custom_type i)) or by pointer (void g(struct custom_type* i)).
With POD values (int, char, etc.) passing by value is not a problem, but if you are looking at complex structures, then the stack grows too quickly by placing entire structures on stack for function calls. That is why in C you tend to pass structures as parameters by pointer, even if the function doesn't modify them.
In C++ there are cases where neither option worked:
passing by pointers involves a counter-intuitive syntax for operators (if you define operator + for a class custom_type writing custom_type a, b, c; a = &b + &c; is counterintuitive as a doesn't get assigned the sum of the addresses. Furthermore if you wanted to be able to assign the sum of the values to a and the sum of the addresses to a, you would have to somehow differentiate between the cases, by syntax).
passing by value is impossible or undesired in the case of copy constructors. In your case, if you have Date(Date d) {} and assignment Date a; Date b(a); what you get is that a copy of a is created just to be passed as a parameter to the constructor of b. This leads to infinite recursion, as creating a copy of a to pass as a parameter involves is the same as Date d = a; b = Date(d);.
For these reasons (and there may have been others) a decision was made to create references: data types that looks syntactically like a value type, but behave like pointers (that is, it points to the value of another variable, but you access it like a variable, not like a pointer).
Regarding the reason why you need const in the declaration, it is so that your constructor will accept temporary objects. As you cannot modify the value of a temporary references if your constructor doesn't accept const& you can only use the copy constructor for non-const stable objects.
That is, if you have:
class Date
{
public:
Date(Date& other); // non-const reference
...
you can write:
Date a;
Date b = a;
but not:
Date someFunction() { return Date(xxx); }
Date a = someFunction(); // someFunction returns a temporary object
neither:
const Date someImportantDate;
Date a = someImportantDate; // cannot pass const value to non-const