Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

constructor called twice, destructor called 3 times

Posted on 2014-02-13
10
Medium Priority
?
387 Views
Last Modified: 2014-02-13
I set breakpoints on the constructor and destructor. The constructor is called 2 times. The destructor is called 3 times. What am I doing wrong (besides choosing C++ as a language to program in)?

ClassC.cpp line 17 below, can I do that return?

(My ClassD holds an int which I set and change to help me keep track of which class instance is which.)

ClassD.h
#pragma once
class ClassD
{
public:
  ClassD(int j);
  ~ClassD(void);
  void Test(int j);
private:
  int i;
};

Open in new window

ClassD.cpp
#include "StdAfx.h"
#include "ClassD.h"


ClassD::ClassD(int j) : i(j)
{
}


ClassD::~ClassD(void)
{
  int j = i;
}


void ClassD::Test(int j)
{
  i = j;
}

Open in new window

ClassC.h
#pragma once
#include "ClassA.h"
#include "ClassD.h"

class ClassC : public ClassA
{
public:
  ClassC(void);
  ~ClassC(void);
  ClassD ReturnClassInstance(void);
};

Open in new window

ClassC.cpp
#include "StdAfx.h"
#include "ClassC.h"
#include "ClassD.h"

ClassC::ClassC(void)
{
}

ClassC::~ClassC(void)
{
}

ClassD ClassC::ReturnClassInstance(void)
{
  ClassD dd(10);
  dd.Test(3);
  return dd;  //can I do this?
}

Open in new window

main code
#include "stdafx.h"
#include "ClassC.h"
#include "ClassD.h"

int _tmain(int argc, _TCHAR* argv[])
{
  ClassC c;
  ClassD d(5);

  d.Test(2);
  d = c.ReturnClassInstance();
  d.Test(7);

  return 0;
}

Open in new window

0
Comment
Question by:deleyd
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 4
  • 2
10 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 1600 total points
ID: 39856592
This is because you aren't providing a cusom copy constructor, but are relying on the compiler-generated one, which you won't 'see' (or encountern) when debugging your code. The copy ctor is invoked implicitly when you call 'ReturnClassInstance()'. You can see the correct behaviour when creating your own copy constructor, e.g.

#pragma once
class ClassD
{
public:
  ClassD(int j);
  ClassD(const ClassD& r); // copy constructor
  ~ClassD(void);
  void Test(int j);
private:
  int i;
};
                                  

Open in new window

#include "StdAfx.h"
#include "ClassD.h"


ClassD::ClassD(int j) : i(j)
{
}

ClassD::ClassD(const ClassD& r)  // copy constructor
{
  i = r.i;
}

ClassD::~ClassD(void)
{
  int j = i;
}


void ClassD::Test(int j)
{
  i = j;
}
                                  

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 39856608
BTW, to elaborate: Usually, a copy constructor (http://en.wikipedia.org/wiki/Copy_constructor) is not necessary as in simple cases as yours, only in more complicated setups where complex members and/or pointers are involved. Nevertheless, the compiler will create one implicitly for temporary objects, as in your case. And the destructors for these temp. objects will of course be invoked automatically, which leads to observations like theone you have seen, since you are explicitly providing a destructor - which, as well, is not necessary in your case, since there is nothing to explicitly deallocate or clean up.
0
 
LVL 35

Expert Comment

by:sarabande
ID: 39856622
in the main function you create a ClassD d and the constructor was called.

in function ClassC::ReturnClassInstance you create dd an instance of ClassD where the constructor was called.

At the return statement you return the dd, so the compiler creates a copy of the dd. as you don't have implemented a copy constructor the compiler created a default copy constructor which you couldn't step into as there is no source code available. when the scope of the function was left the destructor was called first time for the local dd.

in main function after return both d and the temporary copy of the dd were deleted, so the destructor was called two times.

Sara
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 86

Assisted Solution

by:jkr
jkr earned 1600 total points
ID: 39856627
I'm getting old - also important in this context: The assignment operator - see http://en.wikipedia.org/wiki/Assignment_operator_in_C%2B%2B

This one basically would be quite similar like

#pragma once
class ClassD
{
public:
  ClassD(int j);
  ClassD(const ClassD& r); // copy constructor
  ClassD& operator=(const ClassD& r); // assignment operator
  ~ClassD(void);
  void Test(int j);
private:
  int i;
};
                                  
                          

Open in new window


#include "StdAfx.h"
#include "ClassD.h"


ClassD::ClassD(int j) : i(j)
{
}

ClassD::ClassD(const ClassD& r)  // copy constructor
{
  i = r.i;
}

ClassD& ClassD::operator=(const ClassD& r)  // assignment operator
{
  i = r.i;

 return *this; // return reference to self
}
ClassD::~ClassD(void)
{
  int j = i;
}


void ClassD::Test(int j)
{
  i = j;
}
                                  
                          

Open in new window

0
 
LVL 35

Expert Comment

by:sarabande
ID: 39856653
sorry. I didn't refresh before posting.

see my comment as an add-on to the explanations jkr has made.

Sara
0
 
LVL 35

Assisted Solution

by:sarabande
sarabande earned 400 total points
ID: 39856784
to add:

the copy constructor was called when the dd was returned in ReturnClassInstance.

the assignment operator was called when the return value of ReturnClassInstance was assigned to the already constructed d object.

note, if you would have a statement like

ClassD ddd = c.ReturnClassInstance(); 

Open in new window


the copy constructor would be called and not the operator=. that is different to your case.

Usually, a copy constructor <...> is not necessary as in simple cases as yours, only in more complicated setups where complex members and/or pointers are involved.


Actually, a copy constructor and an operator= should only be added if pointers are involved. complex members should/must have a proper copy constructor/operator= themselves and therefore a default member-wise copy of your class would call them automatically. providing your own copy functionality if not necessary is error-prone as you have to care for them whenever you do a change. on the other hand, if there are member pointers or member containers with pointers you have to provide a copy functionality, as the default implementation would only copy the pointer's value, the address of the object and not the object itself (flat copy). that is bad as you now have two instances using the same pointer and none of them could delete it without making it invalid for the other. because of that you should avoid pointer members. if that is not possible, you also could prevent your class being copied at all. that could be done by providing a private copy constructor and a private operator=.

class ClassD
{
private:
     ClassD(const ClassD &) { }
     ClassD & operator=(const ClassD &) { return this; }
     ...

Open in new window

then, the compiler would complain for each attempt to make a copy of your class from a global function or a non-member function of ClassD.

Sara
0
 

Author Comment

by:deleyd
ID: 39856936
Sara line 5
ClassD & operator=(const ClassD &) { return this; }

Open in new window

would that be return *this; ?

Oh, and is there a way in Visual Studio to get the address of a variable such as dd holding a class?
0
 
LVL 86

Expert Comment

by:jkr
ID: 39856961
>>would that be return *this; ?

Yes,

ClassD & operator=(const ClassD &) { return this; }
                                            

Open in new window


would just result in a compile error.

>>Oh, and is there a way in Visual Studio to get the address of a variable such as dd
>>holding a class?

Since 'dd' is a local variable, it is located on the stack, so the actual address won't help much. The address will not be valid any more after 'ReturnClassInstance()' exits, a copy is created that is placed on the stack of the calling function, in your case 'main()'.
0
 

Author Closing Comment

by:deleyd
ID: 39856988
I think I understand what's happening now.

ClassD d(5); //create 1st instance

Then a lot happens at this line:
d = c.ReturnClassInstance();

  ClassD dd(10);   //create 2nd instance
  dd.Test(3);
  return dd;    //copy constructor creates 3rd instance

3rd instance returned. 2nd instance deleted when dd goes out of scope on return.

Then the assignment:
d = c.ReturnClassInstance();

3rd instance copied to d (assignment operator =)

3rd instance deleted.

and we're finally done with that call.

d deleted on program exit

(I think to prevent class not being copied at all, in addition to making the copy constructor and = operator private, also don't include an implementation for either, so compiler with catch if class itself tries to make a copy.)
0
 
LVL 35

Expert Comment

by:sarabande
ID: 39858367
I think to prevent class not being copied at all, in addition to making the copy constructor and = operator private, also don't include an implementation for either, so compiler with catch if class itself tries to make a copy
you could add an assertion into the body of the implementation such that an accidental call of the copy functionality from a member function could be detected. but you are right, if you do just nothing in the copy constructor beside of initializing all members with defaults, the copy is just empty and could cause much less harm as it would do by copying pointers.

Sara
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

721 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question