copy construction

T

trying_to_learn

i am on the chapter on copy construction in C++
in the code (see below), the author says if u pass the object by value
as in HowMany h2 = f(h); ....then a bitwise object is created w/o
calling the constructor of the class. However he says when we leave
scope of function HowMany f(HowMany x) then the destructor is called.
why this inconsistency?. Accdng to me even the destructor should *not*
be called. i can understand that bit wise copy means a 'C' like method
of simply pushing the arguments into stack. accdng to me when fn 'f' is
over, it should simply mean that stack (local object that was made by
value)is popped out without calling its detructor.

i hope im not asking a stupid qn. but im confused abt this fundamental.

-----------------*heres the code*------------------------------

class HowMany {
static int objectCount;
public:
HowMany() { objectCount++; }
static void print(const string& msg = "") {
if(msg.size() != 0) out << msg << ": ";
out << "objectCount = "
<< objectCount << endl;
}
~HowMany() {
objectCount--;
print("~HowMany()");
}
};
int HowMany::eek:bjectCount = 0;

// Pass and return BY VALUE:
HowMany f(HowMany x) {
x.print("x argument inside f()");
return x;
}

int main() {
HowMany h;
HowMany::print("after construction of h");
HowMany h2 = f(h);
HowMany::print("after call to f()");
} ///:~
 
A

angelo

trying_to_learn said:
i am on the chapter on copy construction in C++
in the code (see below), the author says if u pass the object by value
as in HowMany h2 = f(h); ....then a bitwise object is created w/o
calling the constructor of the class. However he says when we leave
scope of function HowMany f(HowMany x) then the destructor is called.
why this inconsistency?. Accdng to me even the destructor should *not*
be called. i can understand that bit wise copy means a 'C' like method
of simply pushing the arguments into stack. accdng to me when fn 'f' is
over, it should simply mean that stack (local object that was made by
value)is popped out without calling its detructor.

i hope im not asking a stupid qn. but im confused abt this fundamental.

-----------------*heres the code*------------------------------

class HowMany {
static int objectCount;
public:
HowMany() { objectCount++; }
static void print(const string& msg = "") {
if(msg.size() != 0) out << msg << ": ";
out << "objectCount = "
<< objectCount << endl;
}
~HowMany() {
objectCount--;
print("~HowMany()");
}
};
int HowMany::eek:bjectCount = 0;

// Pass and return BY VALUE:
HowMany f(HowMany x) {
x.print("x argument inside f()");
return x;
}

int main() {
HowMany h;
HowMany::print("after construction of h");
HowMany h2 = f(h);
HowMany::print("after call to f()");
} ///:~
The reason is that, because you don't have a user defined copy
constructor for class HowMany, the compiler generated one for you (of
course you cannot see any sign of it being called). When h is passed by
value, the automatically augmented copy constructor, whose behavior in
this case is simply doing bitwise copy, is called, though it cannot see
it being called. So actually the symmetry still exists, with the copy
constructor invisible to you.
 
E

E. Robert Tisdale

trying_to_learn said:
I am [reading] the chapter on copy construction in C++. In the code (see below),
the author says [that], if I pass the object by value as in HowMany h2 = f(h),
then a bitwise object is created w/o calling the constructor of the class.
However, he says [that], when [the thread of execution]
leaves scope of function f(HowMany), then the destructor is called.

To make a copy of h to "pass by value".
Why this inconsistency? According to me even the destructor should *not*
be called. I can understand that bit wise copy means a 'C' like method
of simply pushing the arguments into stack.

According to me, when f(HowMany) returns, it should simply mean that the stack
(local object that was made by value) is popped out without calling its destructor.

Actually, your C/C++ compiler emits code to do this automatically.
But it calls your "destructor" to "clean up" first.
If, for example, your constructor called new to allocate memory for a
pointer data member in one of your objects,
your destructor should call delete to deallocate that memory
*before* the object is "popped off of the stack".
I hope [that] I'm not asking a stupid question
but I'm confused about this fundamental.
-----------------*heres the code*------------------------------

cat main.cc
#include <iostream>

class HowMany {
private:
static int objectCount;
public:
static void print(const std::string& msg = "") {
if(0 != msg.size())
std::clog << msg << ": ";
std::clog << "objectCount = " << objectCount << std::endl;
}
HowMany(void) {
++objectCount;
print("HowMany::HowMany(void)");
}
HowMany(const HowMany& n) {
++objectCount;
print("HowMany::HowMany(const HowMany&)");
}
~HowMany(void) {
--objectCount;
print("HowMany::~HowMany(void)");
}
};

int HowMany::eek:bjectCount = 0;

// Pass and return BY VALUE:
HowMany f(HowMany x) {
x.print("x argument inside f(HowMany)");
return x;
}

int main(int argc, char* argv[]) {
HowMany h;
HowMany::print("after construction of h");
HowMany h2 = f(h);
HowMany::print("after call to f()");
return 0;
}
g++ -Wall -ansi -pedantic -o main main.cc
./main
HowMany::HowMany(void): objectCount = 1
after construction of h: objectCount = 1
HowMany::HowMany(const HowMany&): objectCount = 2
x argument inside f(HowMany): objectCount = 2
HowMany::HowMany(const HowMany&): objectCount = 3
HowMany::~HowMany(void): objectCount = 2
after call to f(): objectCount = 2
HowMany::~HowMany(void): objectCount = 1
HowMany::~HowMany(void): objectCount = 0
 
J

John Harrison

trying_to_learn said:
i am on the chapter on copy construction in C++
in the code (see below), the author says if u pass the object by value as
in HowMany h2 = f(h); ....then a bitwise object is created w/o calling
the constructor of the class.

That's rubbish. In C++ class objects are *never* created without calling a
class constructor. Probably the point the author is trying to make is that
in the example below it is the compiler generated copy constructor that is
called. But even then the author should appeciate that a compiler generated
copy constructor is *not* a bitwise copy and there is no such thing as a
bitwise object.

This sound like Bullschildt, who is the author?

If you add your own copy constructor to HowMany, then you will see that it
is called when you pass an object by value.

class HowMany {
static int objectCount;
public:
HowMany() { objectCount++; }

// copy constructor
HowMany(const HowMany& rhs) { objectCount++; }
However he says when we leave scope of function HowMany f(HowMany x) then
the destructor is called.
why this inconsistency?. Accdng to me even the destructor should *not* be
called. i can understand that bit wise copy means a 'C' like method of
simply pushing the arguments into stack. accdng to me when fn 'f' is over,
it should simply mean that stack (local object that was made by value)is
popped out without calling its detructor.

Everytime a class object is created a constructor is called (even if it is a
compiler generated one). Every time a class object is destroyed a destructor
is called (even if it is a compiler generated one). There is no such thing
as a bitwise object or a bitwise copy in C++.
i hope im not asking a stupid qn. but im confused abt this fundamental.

No I think you have a stupid author who is trying to make the simple
complicated.

john
 
H

Heinz Ozwirk

trying_to_learn said:
i am on the chapter on copy construction in C++
in the code (see below), the author says if u pass the object by value
as in HowMany h2 = f(h); ....then a bitwise object is created w/o
calling the constructor of the class.

That is simply wrong. If you don't implement your own copy constructor, your compiler will do that for you, and it will call that constructor. However, this compiler generated copy constructor does not do a bitwise copy. It does a memberwise copy, that is, it calls the copy constructors for all data members.

HTH
Heinz
 
T

trying_to_learn

trying_to_learn said:
i am on the chapter on copy construction in C++
in the code (see below), the author says if u pass the object by value
as in HowMany h2 = f(h); ....then a bitwise object is created w/o
calling the constructor of the class. However he says when we leave
scope of function HowMany f(HowMany x) then the destructor is called.
why this inconsistency?. Accdng to me even the destructor should *not*
be called. i can understand that bit wise copy means a 'C' like method
of simply pushing the arguments into stack. accdng to me when fn 'f' is
over, it should simply mean that stack (local object that was made by
value)is popped out without calling its detructor.

i hope im not asking a stupid qn. but im confused abt this fundamental.

-----------------*heres the code*------------------------------

class HowMany {
static int objectCount;
public:
HowMany() { objectCount++; }
static void print(const string& msg = "") {
if(msg.size() != 0) out << msg << ": ";
out << "objectCount = "
<< objectCount << endl;
}
~HowMany() {
objectCount--;
print("~HowMany()");
}
};
int HowMany::eek:bjectCount = 0;

// Pass and return BY VALUE:
HowMany f(HowMany x) {
x.print("x argument inside f()");
return x;
}

int main() {
HowMany h;
HowMany::print("after construction of h");
HowMany h2 = f(h);
HowMany::print("after call to f()");
} ///:~
Thankyou all for ure replies
I am quoting directly from the book thinking in C++ and have put the
sentence in bold where the author says bitcopy is used and constructor
is not called.

Quote Start:
"Look at the point inside f( ), which occurs after the argument is
passed by value. This means the original object h exists outside the
function frame, and there’s an additional object inside the function
frame, which is the copy that has been passed by value. However,
the argument has been passed using C’s primitive notion of
bitcopying, whereas the C++ HowMany class requires true
initialization to maintain its integrity, so the default bitcopy fails to
produce the desired effect.
When the local object goes out of scope at the end of the call to f( ),
the destructor is called, which decrements objectCount, so outside
the function, objectCount is zero. *The creation of h2 is also
performed using a bitcopy, so the constructor isn’t called there
either*, and when h and h2 go out of scope, their destructors cause
the negative values of objectCount."

End Quote
 
A

angelo

trying_to_learn said:
Quote Start:
"Look at the point inside f( ), which occurs after the argument is
passed by value. This means the original object h exists outside the
function frame, and there’s an additional object inside the function
frame, which is the copy that has been passed by value. However,
the argument has been passed using C’s primitive notion of
bitcopying, whereas the C++ HowMany class requires true
initialization to maintain its integrity, so the default bitcopy fails to
produce the desired effect.
When the local object goes out of scope at the end of the call to f( ),
the destructor is called, which decrements objectCount, so outside
the function, objectCount is zero. *The creation of h2 is also
performed using a bitcopy, so the constructor isn’t called there
either*, and when h and h2 go out of scope, their destructors cause
the negative values of objectCount."

End Quote

I think it's also correct to say that the copy constructor is not called
in this case. Although *conceptually* an augmented copy constructor is
provided by the compiler, it also can just insert the something like
push instructions into the code, to have the effect of bitwise copy.
But for your destructor, since its defined by yourself, it must be
executed. However, if you don't define it, the compiler would also
augment one for you, which may not do anything and thus skipped.
Please note that the compiler-augmented copy constructor *conceptually*
exists, but may or may not be actually.
 
J

John Harrison

trying_to_learn said:
Thankyou all for ure replies
I am quoting directly from the book thinking in C++ and have put the
sentence in bold where the author says bitcopy is used and constructor
is not called.

Quote Start:
"Look at the point inside f( ), which occurs after the argument is
passed by value. This means the original object h exists outside the
function frame, and there’s an additional object inside the function
frame, which is the copy that has been passed by value. However,
the argument has been passed using C’s primitive notion of
bitcopying,

Since HowMany contains no data at all, its hard to see why the author thinks
a bit copy is occuring.
whereas the C++ HowMany class requires true
initialization to maintain its integrity, so the default bitcopy fails to
produce the desired effect.

The author is also incorrect in his implication that if you fail to provide
a copy constructor then the default is bitwise copying. It perfectly
possible to write a class where a bitwise copy would occur, but its also
possible to write one where it wouldn't. If you fail to provide a copy
constructor the default is *memberwise* copying not bitwise copying.
Memberwise copying may be the same as bitwise copying but it may not, it all
depends on the class

When the local object goes out of scope at the end of the call to f( ),
the destructor is called, which decrements objectCount, so outside
the function, objectCount is zero. *The creation of h2 is also
performed using a bitcopy, so the constructor isn’t called there
either*, and when h and h2 go out of scope, their destructors cause
the negative values of objectCount."

End Quote

I think the bottom line is that the author has written a deliberately bad
piece of C++ code to illustrate a point, and confused you in the process,
presumably because you don't think it should be possible to write bad code
like that. Unfortunately it is.

john
 
R

Ron Natalie

angelo said:
. Although *conceptually* an augmented copy constructor is
provided by the compiler, it also can just insert the something like
push instructions into the code, to have the effect of bitwise copy.

I would like to go back in time and remove whatever reference started
all this "bitwise" copy non-sense. C++ does not in theory or practice
ever copy things "bitwise."

You can't even make the assumption "conceptually." The lack of a user
defined copy constructor means that there is a subobject by subobject copy
performed. While in the case of POD types the compiler may, in fact,
do a block memory copy of some sort, if the class is NOT POD, the compiler
generated copy has to copy each member by it's respective copy constructor.

For exmaple:
struct foo {
std::string s;
};

The compiler can't "bitwise" copy anything here. It has to generate a
copy constructor that is the equivelent of:
foo::foo(const foo& that) s(that.s) { }
 
A

angelo

Ron said:
I would like to go back in time and remove whatever reference started
all this "bitwise" copy non-sense. C++ does not in theory or practice
ever copy things "bitwise."
I admit that the term "bitwise" is not used for copy constructor in the
Standard, and that's what we say is "in theory", right?
But in practice you can see too many places, formally or informally,
occur the worde "bitwise".
You can't even make the assumption "conceptually."
See the Standard 12.8.1, the second sentence is:
*Conceptually*, these operations are implemented by a copy constructor
and a copy assignment operator.
For exmaple:
struct foo {
std::string s;
};

The compiler can't "bitwise" copy anything here. It has to generate a
copy constructor that is the equivelent of:
foo::foo(const foo& that) s(that.s) { }
Of course so. But I guess most of us do know about this. What we are
talking about is when the class *is* POD. See Inside the C++ Object
Model 2.2,
----------------------------------------------------------------------
How is this operation in practice carried out? The original ARM tells us:
Conceptually, for a class X [this operation is] implemented by…a copy
constructor.
The operative word here is conceptually. The commentary that follows
explains:
In practice, a good compiler can generate bitwise copies for most
class objects since they have bitwise copy semantics….
That is, a copy constructor is not automatically generated by the
compiler for each class that does not explicitly define one. Rather, as
the ARM tells us,
Default constructors and copy constructors…are generated (by the
compiler) where needed.
Needed in this instance means when the class does not exhibit bitwise
copy semantics.
 
R

Ron Natalie

angelo said:
I admit that the term "bitwise" is not used for copy constructor in the
Standard, and that's what we say is "in theory", right?
But in practice you can see too many places, formally or informally,
occur the worde "bitwise".

The practice is wrong in too many places. Copying is NOT done conceptually
or in practice "bitwise" nor has it ever been done.


Default constructors and copy constructors…are generated (by the
compiler) where needed.
Needed in this instance means when the class does not exhibit bitwise
copy semantics.

Note that nont having user declared construction is NOT equivelent to
being POD.

It's better to use the right concepts with the language than to stumble
all over these misconceptions.
 
A

angelo

Ron said:
Copying is NOT done conceptually or in practice "bitwise" nor has it ever been done.
How do you know that? Have you studied all the compilers on this?
Note that nont having user declared construction is NOT equivelent to
being POD.
I didn't say that, and cannot figure out how you can come to this
conclusion from my words.
It's better to use the right concepts with the language than to stumble
all over these misconceptions.
I don't think those sentences stated in ARM is misconceptions.
 
P

Peter Koch Larsen

Ron Natalie said:
angelo wrote: [snip]

I would like to go back in time and remove whatever reference started
all this "bitwise" copy non-sense. C++ does not in theory or practice
ever copy things "bitwise."
[snip]

A historical note:

Once upon a time, long time before standardization, the default
copy-constructor would do a bit-wise copy. It did not take very long before
that was changed to a member-wise copy. This fact could be the root of this
confusion.

/Peter
 
R

Ron Natalie

Peter said:
Once upon a time, long time before standardization, the default
copy-constructor would do a bit-wise copy. It did not take very long before
that was changed to a member-wise copy. This fact could be the root of this
confusion.
I still doubt it was bitwise. Almost every C and C++ implementation
moves things at least in terms of bytes.
 
P

Peter Koch Larsen

Ron Natalie said:
I still doubt it was bitwise. Almost every C and C++ implementation
moves things at least in terms of bytes.
Trust me - it was bitwise. He mentioned it in one of his earlier books,
perhaps "Design and Evolution of C++".
That bitwise copy-construction probably ceased to be the norm when the
number of C++-users came over 100 - it must have been a very early compiler,
surely.

/Peter
 

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,999
Messages
2,570,243
Members
46,835
Latest member
lila30

Latest Threads

Top