Confused by the constructor and cop-constructor.

X

Xiangliang Meng

The fragment code:

#include <iostream>
using namespace std;

class Integer {
int i;
public:
Integer() : i(0) {};

Integer(int I) : i(I) {};
Integer(Integer & other) : i(other.i) {} // line 10
Integer & operator=(Integer &other) {
i = other.i;
return (* this);
}
Integer & operator=(int a) {
i = a;
return (* this);
}
friend ostream& operator<<(ostream &os, Integer &I) {
os << I.i;
return os;
}
};

int main() {
int a = 5;
Integer Int1 = a; // line 27; error happens here.
Integer Int2 = Int1; // line 28;

cout << Int1 <<", " << Int2 << endl;
Int1 = 5; // line 31
cout << Int1 <<", " << Int2 << endl;
Int2 = Int1; // line 33
cout << Int1 <<", " << Int2 << endl;
}

case 1: If the line 10 is there, compiling aborts at line 27.
g++.exe "Integer.cpp" -o
Integer.exe" -g3 -I"d:\Dev-Cpp\include\c++" -I"d:\Dev-Cpp\include\c++\mi
ngw32" -I"d:\Dev-Cpp\include\c++\backward" -I"d:\Dev-Cpp\include" -L"d:\
Dev-Cpp\lib"
Integer.cpp: In function `int main()':
Integer.cpp:27: no matching function for call to `Integer::Integer(Integer)'
Integer.cpp:10: candidates are: Integer::Integer(Integer&)
Integer.cpp:9: Integer::Integer(int)
Integer.cpp:27: initializing temporary from result of `

case 2: If the line 10 is delete, there is no error at line 27 when
compiling.

Could someone explain this for me?

What does line 27 do in detail? Invoke Integer::Integer(int I) directly? or
Create a temporary Integer object from the variable 'a' and use
copy-constructor to create Int1 from this termporary object?

Could someone explain more in details on line 27, 28, 31 and 33? What's the
difference among them?

Thanks a lot.

Best Regards,

Xiangliang Meng
 
A

Alan Johnson

Xiangliang said:
The fragment code:

#include <iostream>
using namespace std;

class Integer {
int i;
public:
Integer() : i(0) {};

Integer(int I) : i(I) {};
Integer(Integer & other) : i(other.i) {} // line 10
Integer & operator=(Integer &other) {
i = other.i;
return (* this);
}
Integer & operator=(int a) {
i = a;
return (* this);
}
friend ostream& operator<<(ostream &os, Integer &I) {
os << I.i;
return os;
}
};

int main() {
int a = 5;
Integer Int1 = a; // line 27; error happens here.
Integer Int2 = Int1; // line 28;

cout << Int1 <<", " << Int2 << endl;
Int1 = 5; // line 31
cout << Int1 <<", " << Int2 << endl;
Int2 = Int1; // line 33
cout << Int1 <<", " << Int2 << endl;
}

case 1: If the line 10 is there, compiling aborts at line 27.
g++.exe "Integer.cpp" -o
Integer.exe" -g3 -I"d:\Dev-Cpp\include\c++" -I"d:\Dev-Cpp\include\c++\mi
ngw32" -I"d:\Dev-Cpp\include\c++\backward" -I"d:\Dev-Cpp\include" -L"d:\
Dev-Cpp\lib"
Integer.cpp: In function `int main()':
Integer.cpp:27: no matching function for call to `Integer::Integer(Integer)'
Integer.cpp:10: candidates are: Integer::Integer(Integer&)
Integer.cpp:9: Integer::Integer(int)
Integer.cpp:27: initializing temporary from result of `

case 2: If the line 10 is delete, there is no error at line 27 when
compiling.

Could someone explain this for me?

What does line 27 do in detail? Invoke Integer::Integer(int I) directly? or
Create a temporary Integer object from the variable 'a' and use
copy-constructor to create Int1 from this termporary object?

Could someone explain more in details on line 27, 28, 31 and 33? What's the
difference among them?

Thanks a lot.

Best Regards,

Xiangliang Meng

This doesn't particularly answer all your questions, but you can get rid
of the compiler error if you change line 10 to:

Integer(const Integer & other) : i(other.i) {}

I'll try later to look it up and see exactly why the error you are
getting occurs, if nobody beats me to it.

Alan
 
J

JKop

I've fiddled with the code a little. The following compiles:

#include <iostream>

using namespace std;

class Integer {
private:

int i;

public:

Integer() : i(0) {;}
Integer(int I) : i(I) {;}

//Instead of the two above you could have:
//Integer(int I = 0) : i(I) {;}

Integer(Integer& other) : i(other.i) {;} // line 10


Integer& operator=(Integer& other) {
i = other.i;
return (* this);
}

Integer& operator=(int a) {
i = a;
return (* this);
}

friend ostream& operator<<(ostream &os, Integer &I) {
os << I.i;
return os;
}
};


int main()
{
int monkey = 72;

Integer Int1(monkey); //THE MAGICAL LINE

Integer Int2 = Int1;

cout << Int1 <<", " << Int2 << endl;

Int1 = 5;
cout << Int1 <<", " << Int2 << endl;

Int2 = Int1;
cout << Int1 <<", " << Int2 << endl;
}



I am at a loss to why, with THE MAGICAL LINE above:

Integer Int1(monkey);


will compile, while:


Integer Int1 = monkey;

won't!! Is this a compiler bug, because both statements should be EXACTLY
THE SAME?


-JKop
 
K

Karl Heinz Buchegger

Xiangliang said:
The fragment code:

#include <iostream>
using namespace std;

class Integer {
int i;
public:
Integer() : i(0) {};

Integer(int I) : i(I) {};
Integer(Integer & other) : i(other.i) {} // line 10
Integer & operator=(Integer &other) {
i = other.i;
return (* this);
}
Integer & operator=(int a) {
i = a;
return (* this);
}
friend ostream& operator<<(ostream &os, Integer &I) {
os << I.i;
return os;
}
};

int main() {
int a = 5;
Integer Int1 = a; // line 27; error happens here.
Integer Int2 = Int1; // line 28;

cout << Int1 <<", " << Int2 << endl;
Int1 = 5; // line 31
cout << Int1 <<", " << Int2 << endl;
Int2 = Int1; // line 33
cout << Int1 <<", " << Int2 << endl;
}

case 1: If the line 10 is there, compiling aborts at line 27.
g++.exe "Integer.cpp" -o
Integer.exe" -g3 -I"d:\Dev-Cpp\include\c++" -I"d:\Dev-Cpp\include\c++\mi
ngw32" -I"d:\Dev-Cpp\include\c++\backward" -I"d:\Dev-Cpp\include" -L"d:\
Dev-Cpp\lib"
Integer.cpp: In function `int main()':
Integer.cpp:27: no matching function for call to `Integer::Integer(Integer)'
Integer.cpp:10: candidates are: Integer::Integer(Integer&)
Integer.cpp:9: Integer::Integer(int)
Integer.cpp:27: initializing temporary from result of `

case 2: If the line 10 is delete, there is no error at line 27 when
compiling.

Could someone explain this for me?

Integer Int1 = a; // line 27; error happens here.

Here a temporary Integer object is created from a. This temporary
is then feed into the copy constructor to create Int1.

The signature of your copy constructor is:

Integer(Integer & other) : i(other.i) {} // line 10

But a temporary cannot be bound to a reference which is not
const! Thus the error.

If you don't write the copy constructor yourself, the compiler
generates one. But the compiler generated has the signature

Integer( const Integer & other) : i(other.i) {} // line 10

See the difference?

This difference is, why the compiler generated one works, while yours
doesn't.
What does line 27 do in detail? Invoke Integer::Integer(int I) directly? or
Create a temporary Integer object from the variable 'a' and use
copy-constructor to create Int1 from this termporary object?

The later one.
Could someone explain more in details on line 27, 28, 31 and 33? What's the
difference among them?

27: Integer Int1 = a;

object gets created -> constructor is used,
Thus 'a' first has to be transformed into an Integer
object, use the ctor which takes an int for that.

28: Integer Int2 = Int1;

object gets created -> constructor is used
Since Int1 is already an Integer object, use the copy
constructor for Int2

31: Int1 = 5;

This is an assignment. Thus an opertor= is used.
First try to find something that allows an int to be assigned
directly to an Integer ->
Integer & operator=(int a)
is found and used

33: Int2 = Int1;

This is an assignment. Thus an operator= is used.
Find an operator= which can take an Integer object ->
Integer & operator=(Integer &other)
is found and used.
 
K

Karl Heinz Buchegger

I am at a loss to why, with THE MAGICAL LINE above:

Integer Int1(monkey);

will compile, while:

Integer Int1 = monkey;

won't!! Is this a compiler bug, because both statements should be EXACTLY
THE SAME?

No they are not.

In

Integer Int1 = monkey;

first a temporary Integer object is created from monkey, which is
then used with the copy constructor to initialize Int1

while in
Integer Int1(monkey);

The constructor taking an int is used.

Integer Int1 = monkey;
is equivalent to
Integer Int1 ( Integer( monkey ) );

Don't worry about the temporary object. The compiler is allowed to optimize
it away in all circumstances (even if the copy constructor has side
effects) and will normally do so.
 
X

Xiangliang Meng

Hi, all

The behavior is different from our imagination. This is very surprising for
me too. Although I was not sure several hours ago, I thought there is a
temporary object will be created in this scenario.
int a = 5;
Integer Int1 = a;
It, however, is the same as Integer Int1(a). I do not know whether the
compile does optimize to some extent in this line. If so, the compile might
replace creating temporay object with invoking the constructor directly.

The output result is:
Integer::Integer(int I) //**** here is it. This means no temporary object is
created for invoking copy-constructor.
Integer::Integer(const Integer & other)
5.10, 5.10
Integer::eek:perator=(int a)
5.10, 5.10
Integer::eek:perator=(Integer &other)
5.10, 5.10

The new cold with a little change:
#include <iostream>
using namespace std;

class Integer {
int i;
int j; // I add this new data member and hope it could prevent the
compile do optimize in that procedure.
public:
Integer() : i(0), j(0) {
cout << "Integer::Integer()" << endl;
}
Integer(int I) : i(I), j(I*2) {
cout << "Integer::Integer(int I)" << endl;
}
Integer(const Integer & other) : i(other.i), j(other.j) {
cout << "Integer::Integer(const Integer & other)" << endl;
}
Integer & operator=(Integer &other) {
i = other.i;
j = other.j;
cout << "Integer::eek:perator=(Integer &other)" << endl;
return (* this);
}
Integer & operator=(int a) {
i = a;
j = a * 2;
cout << "Integer::eek:perator=(int a)" << endl;
return (* this);
}
friend ostream& operator<<(ostream &os, Integer &I) {
os << I.i << "." << I.j;
return os;
}
};

int main() {
int a = 5;
Integer Int1(a);
Integer Int2 = Int1;

cout << Int1 <<", " << Int2 << endl;
Int1 = 5;
cout << Int1 <<", " << Int2 << endl;
Int2 = Int1;
cout << Int1 <<", " << Int2 << endl;
}


Xiangliang Meng said:
The fragment code:

#include <iostream>
using namespace std;

class Integer {
int i;
public:
Integer() : i(0) {};

Integer(int I) : i(I) {};
Integer(Integer & other) : i(other.i) {} // line 10
Integer & operator=(Integer &other) {
i = other.i;
return (* this);
}
Integer & operator=(int a) {
i = a;
return (* this);
}
friend ostream& operator<<(ostream &os, Integer &I) {
os << I.i;
return os;
}
};

int main() {
int a = 5;
Integer Int1 = a; // line 27; error happens here.
Integer Int2 = Int1; // line 28;

cout << Int1 <<", " << Int2 << endl;
Int1 = 5; // line 31
cout << Int1 <<", " << Int2 << endl;
Int2 = Int1; // line 33
cout << Int1 <<", " << Int2 << endl;
}

case 1: If the line 10 is there, compiling aborts at line 27.
g++.exe "Integer.cpp" -o
nteger.exe" -g3 -I"d:\Dev-Cpp\include\c++" -I"d:\Dev-Cpp\include\c++\miw32" -I"d:\Dev-Cpp\include\c++\backward" -I"d:\Dev-Cpp\include" -L"d:\
Dev-Cpp\lib"
Integer.cpp: In function `int main()':
Integer.cpp:27: no matching function for call to `Integer::Integer(Integer)'
Integer.cpp:10: candidates are: Integer::Integer(Integer&)
Integer.cpp:9: Integer::Integer(int)
Integer.cpp:27: initializing temporary from result of `

case 2: If the line 10 is delete, there is no error at line 27 when
compiling.

Could someone explain this for me?

What does line 27 do in detail? Invoke Integer::Integer(int I) directly? or
Create a temporary Integer object from the variable 'a' and use
copy-constructor to create Int1 from this termporary object?

Could someone explain more in details on line 27, 28, 31 and 33? What's the
difference among them?

Thanks a lot.

Best Regards,

Xiangliang Meng

Best Regards,

Xiangliang Meng
 
K

Karl Heinz Buchegger

Xiangliang said:
Hi, all

The behavior is different from our imagination. This is very surprising for
me too. Although I was not sure several hours ago, I thought there is a
temporary object will be created in this scenario.
int a = 5;
Integer Int1 = a;

It is. At least conceptually
It, however, is the same as Integer Int1(a).

Its' not the same

An equivalent formulation would be

Integer Int1 ( Integer( a ) );
I do not know whether the
compile does optimize to some extent in this line.

It surely does. This is the only (AFAIK) explicite optimization that is
mentioned in the standards document.
If so, the compile might
replace creating temporay object with invoking the constructor directly.
Yep.


The output result is:
Integer::Integer(int I) //**** here is it. This means no temporary object is
created for invoking copy-constructor.

This does not follow.
What you see here is the constructor which is called to construct the
temporary. Remember above?

Integer Int1( Integer( a ) );

The temporary is constructed by using the constructor which takes an int. But then
magic happens. The compiler aranges such that the temporary is constructed
at the same place as Int1, effectively making it look like the temporary and
the copy constructor are unneccessary.

But you can try the following. Make the copy constructor unaccessible for
the compiler. You then will find that Integer Int1 = a; will no longer
compile, due to lack of copy constructor.
 
V

Victor Bazarov

Xiangliang said:
The fragment code:

#include <iostream>
using namespace std;

class Integer {
int i;
public:
Integer() : i(0) {};

Integer(int I) : i(I) {};
Integer(Integer & other) : i(other.i) {} // line 10
Integer & operator=(Integer &other) {
i = other.i;
return (* this);
}
Integer & operator=(int a) {
i = a;
return (* this);
}
friend ostream& operator<<(ostream &os, Integer &I) {
os << I.i;
return os;
}
};

int main() {
int a = 5;
Integer Int1 = a; // line 27; error happens here.
Integer Int2 = Int1; // line 28;

cout << Int1 <<", " << Int2 << endl;
Int1 = 5; // line 31
cout << Int1 <<", " << Int2 << endl;
Int2 = Int1; // line 33
cout << Int1 <<", " << Int2 << endl;
}

case 1: If the line 10 is there, compiling aborts at line 27.
g++.exe "Integer.cpp" -o
Integer.exe" -g3 -I"d:\Dev-Cpp\include\c++" -I"d:\Dev-Cpp\include\c++\mi
ngw32" -I"d:\Dev-Cpp\include\c++\backward" -I"d:\Dev-Cpp\include" -L"d:\
Dev-Cpp\lib"
Integer.cpp: In function `int main()':
Integer.cpp:27: no matching function for call to `Integer::Integer(Integer)'
Integer.cpp:10: candidates are: Integer::Integer(Integer&)
Integer.cpp:9: Integer::Integer(int)
Integer.cpp:27: initializing temporary from result of `

case 2: If the line 10 is delete, there is no error at line 27 when
compiling.

Could someone explain this for me?

What does line 27 do in detail? Invoke Integer::Integer(int I) directly? or
Create a temporary Integer object from the variable 'a' and use
copy-constructor to create Int1 from this termporary object?

Could someone explain more in details on line 27, 28, 31 and 33? What's the
difference among them?

Line 27 is really

Integer Int1 = Integer(a);

which involves 2 constructors: one parameterized with 'int' and one copy
constructor. However, your copy constructor expects a reference to non-
const Integer. The first (parameterized) constructor here creates
a temporary object, and the call to the copy constructor cannot be made
because a non-const reference cannot be bound to a temporary.

Line 28 is really

Integer Int2(Int1);

which is a copy constructor, but now 'Int1' is not a temporary, but a real
object, and a non-const reference is bound to it without a problem.

Line 31 is a call to the parameterized assignment operator:

Int1.Integer::eek:perator=(5);

You provided it, its argument is 'int', everything is fine.

Line 33 is a call to the copy assignment operator (provided to you by the
compiler, since you haven't defined it yourself):

Int2.Integer::eek:perator=(Int1);

The compiler-provided assignment operator has the signature

Integer& operator=(Integer const&);

The const reference is bound to the object (Int1) without a problem.

HTH

Victor
 
V

Victor Bazarov

Xiangliang said:
The behavior is different from our imagination. This is very surprising for
me too. Although I was not sure several hours ago, I thought there is a
temporary object will be created in this scenario.
int a = 5;
Integer Int1 = a;
It, however, is the same as Integer Int1(a). I do not know whether the
compile does optimize to some extent in this line. If so, the compile might
replace creating temporay object with invoking the constructor directly.

The compiler is allowed to optimise the call to the copy constructor
away, however, it still has to check whether such call could be made
if optimization doesn't take place. In your case, such call cannot
be made, that's what the compiler complains about.

It has nothing to do with imagination. It has everything to do with
the language Standard.

Victor
 
C

Chris Theis

[SNIP]
Integer Int1 ( Integer( a ) );


It surely does. This is the only (AFAIK) explicite optimization that is
mentioned in the standards document.
[SNIP]

There is another explicit optimization that is allowed by the standard,
which might be treated by the compiler rather similarly to this situation.
For example

class CMyObj {
....
};

CMyObj Function() {
CMyObj LocalObj;

return LocalObj; // creates a copy or not?
}

CMyObj Obj = Function();

Here LocalObj might not be copied returning from the function, but the
implementation is allowed to create LocalObj directly into Obj. This is
mentioned in the standard somehwere in the section about copying class
objects.

Cheers
Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top