Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 468
  • Last Modified:

constructor called twice, destructor called 3 times

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
deleyd
Asked:
deleyd
  • 4
  • 4
  • 2
3 Solutions
 
jkrCommented:
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
 
jkrCommented:
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
 
sarabandeCommented:
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
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
jkrCommented:
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
 
sarabandeCommented:
sorry. I didn't refresh before posting.

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

Sara
0
 
sarabandeCommented:
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
 
deleydAuthor Commented:
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
 
jkrCommented:
>>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
 
deleydAuthor Commented:
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
 
sarabandeCommented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 4
  • 4
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now