about copy constructor and destructor

T

Tony Johansson

Hello experts!

I have this piece of code. No user defined copy constructor exist.
AccountForStudent create(long number)
{
AccountForStudent local(number, 0.0);
return local;
}
int main()
{
AccountForStudent global;
global = create(300);

return 0;
}

Here is what happen according to a book.:
1. Program execution enters the body of create(), and the variable local in
initialized by calling the constructor.
2. A temporary variable, temp, created by the compiler, is initialized by
calling the compiler generated copy constructor because no other is defined
and using the value of the local variable.
3. An assignment operator is called, which assign the value of the temporary
variable temp to global.
4.The destructor for the temporary variable temp is called.
5. create() terminates.

Now to my question: temp and local will share the same Student object
because we have a shallow copy.
When the destructor for temp executes the Student object is deallocated and
therefore you now cannot access the Student object through the variable
global.
The strange thing here is first the destuctor for object local must also
have been called.
When this was called and tries to deallocate the Student object that already
has been deallocated by the temp object. This will as I think destroy the
free heap list and cause a crash. Am I right?.

Here is the class definition for AccountForStudent
class AccountForStudent
{
public:
AccountForStudent(long number, double balance);
~AccountForStudent();
long getNumber() const;
. . .
private:
Student* stud_;
double balance_;
};

Many thanks

//Tony
 
V

Victor Bazarov

Tony said:
I have this piece of code. No user defined copy constructor exist.
AccountForStudent create(long number)
{
AccountForStudent local(number, 0.0);
return local;
}
int main()
{
AccountForStudent global;
global = create(300);

return 0;
}

Here is what happen according to a book.:
1. Program execution enters the body of create(), and the variable local in
initialized by calling the constructor.
2. A temporary variable, temp, created by the compiler, is initialized by
calling the compiler generated copy constructor because no other is defined
and using the value of the local variable.
3. An assignment operator is called, which assign the value of the temporary
variable temp to global.
4.The destructor for the temporary variable temp is called.
5. create() terminates.

Actually, I'd move 5 between 2 and 3.
Now to my question: temp and local will share the same Student object
because we have a shallow copy.

How is that? Is 'Student' object in the temporary and 'local' identified
by the pointer and created in the free store by the 'local's constructor?
When the destructor for temp executes the Student object is deallocated and
therefore you now cannot access the Student object through the variable
global.

Actually, this might happen even sooner. When 'local' is destroyed, the
pointer to it (I am assuming it's a pointer) in the temporary becomes
invalid, and while the value of that pointer is copied into 'global', the
validity of it has already been disrupted.
The strange thing here is first the destuctor for object local must also
have been called.

Ah, yes, that's what I just described above.
When this was called and tries to deallocate the Student object that already
has been deallocated by the temp object. This will as I think destroy the
free heap list and cause a crash. Am I right?.

It causes _undefined_behaviour_. Whether that means "crash" or some kind
of destruction "the free heap", I don't know.

The trick here is that the compiler is allowed to employ NRVO (named
return value optimization), and forgo creation of a temporary and use the
'local' object instead. That means only one object will be destroyed
after 'create' function returns, not two.
Here is the class definition for AccountForStudent
class AccountForStudent
{
public:
AccountForStudent(long number, double balance);
~AccountForStudent();
long getNumber() const;
. . .
private:
Student* stud_;
double balance_;
};

V
 
E

E. Robert Tisdale

Tony said:
I have this piece of code. No user defined copy constructor exist.

In effect, the C++ compiler supplies a default copy constructor.
AccountForStudent create(long number) {
AccountForStudent local(number, 0.0);
return local;
}

Why not

AccountForStudent create(long number) {
return local(number, 0.0);
}
int main(int argc, char* argv[]) {
AccountForStudent global;
global = create(300);

return 0;
}

Why not

int main(int argc, char* argv[]) {
AccountForStudent global = create(300);
return 0;
}
Here is what happen according to a book:

Which book?
1. Program execution enters the body of create()
and the variable local in initialized by calling the [explicit] constructor.

No! A good optimizing compiler
will recognize local as an alias for the return value
and initialize it directly -- no local object is created or destroyed.
This is called the Named Return Value Optimization (NRVO).
2. A temporary variable created by the compiler
is initialized by calling the compiler generated copy constructor
because no other is defined and using the value of the local variable.

No!
The compiler emits code to pass a reference to the temporary variable
to function create as a [hidden] argument
which represents the return value.
3. An assignment operator is called
which assign the value of the temporary variable temp to global.
4.The destructor for the temporary variable temp is called.

This is unnecessary if you use create(long) to initialize global
as shown in my example above.
5. create() terminates.

No!
create(long) terminates *before* the assignment.
The temporary variable is created in the scope of the calling program
so it must be destroyed in the scope of the calling program --
after create returns.
Now to my question: temp and local will share the same Student object
because we have a shallow copy.

Meaning, I suppose, that you don't copy the Student object *stud_.
When the destructor for temp executes,
the Student object is deallocated and, therefore,
you now cannot access the Student object through the variable global.

That's stupid.
You need to define a copy constructor and assignment operator
which do a *deep* copy
if you are going to define a "deep" destructor.

The strange thing here is [that]
first the destuctor for object local must also have been called.
When this was called and tries to deallocate the Student object
that already has been deallocated by the temp object.
This will as I think destroy the free heap list and cause a crash.
Am I right?.

You *might* be right.
 
D

Dan Cernat

E. Robert Tisdale said:
Tony Johansson wrote:

Why not

AccountForStudent create(long number) {
return local(number, 0.0);
}
I think you mean
return AccountForStudent (number, 0.0);

/dan
 

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,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top