Avatar billede it-dyret Nybegynder
27. maj 2002 - 00:12 Der er 8 kommentarer og
1 løsning

Passende destructor?!

Jeg sidder og roder med en destructor, men er i tvivl, om den overhovedet virker.

node er af typen TreeNode. Den holder en pointer til en anden TreeNode, som i dette tilfælde fås vha. funktionen getLeftChild().

TreeNode* nodeToMove = node;
nodeToMove = node->getLeftChild();
node->setLeftChild(NULL);
node->setRightChild(NULL);
delete node;
node = nodeToMove;

Spørgsmålet er så nu om den virker rigtigt - og hvis ikke - hvorfor så ikke det?

Jeg har ladet mig fortælle at man i c++ overloader new og delete for at teste sine destructorer. Hvordan gøres dette i mit tilfælde?
Avatar billede it-dyret Nybegynder
27. maj 2002 - 00:17 #1
node skal erstattes med getLeftChild.
Avatar billede soepro Nybegynder
27. maj 2002 - 08:30 #2
Din destructor definition skal altid matche din constructor, dvs. du skal selv lave free af alle de objekter du allokerede. I fht. om nogle af din klasse's member variabler peger på andre objekter har det ingen betydning, hvis ikke du har allokeret dem vha. new i constructoren.

Mht. at "overloade" new og delete for at teste constructor/destructor så har du misforstået overloading begrebet - overloading af en funtion drejer sig om at have flere funktioner med SAMME navn, men forskellige parametre. Overloading sikrer så at compileren vælger den korrekte version i fht. de parametre du angiver. Derimod er det jo sådan at funktionen 'new' kalder klassens constructor, og funktionen delete klassens 'destructor' - måske er det det du mener.

Man overloader ofte constructoren til en klasse, sådan at man kan lave new til den på flere forskellige måder. I dit tree-node eksempel, kunne man forestille sig at man vill kontruere enten en node med to børn, eller en node helt uden. Man kunne så overloade (og her er der tale om overloading) constructoren:

TreeNode::TreeNode(TreeNode left, TreeNode Right)
{
  setLeftChild(left);
  setRightChild(right);
} // Constructor med parametre
TreeNode::TreeNode(void)
{ // Anvend "laveste" contstrutor, dvs. den med flest parametre.
  TreeNode(NULL, NULL);
} // Overloaded constructor UDEN parametre.


HUMLEN ER: Hvis du ikke selv laver new INDEN I CONSTRUCTOREN, skal du heller ikke lave delete i destructoren. I dit eksempel burde den være nok blot at skrive:

TreeNode node = new TreeNode();
:
:
// En masse behandling baseret på node
:
:
delete node; /* Færdig med at bruge den. */
Avatar billede soepro Nybegynder
27. maj 2002 - 08:40 #3
Hvis man f.eks. lavede sin egen lille string klasse, kunne overloadede constructorer og destructorer se sådan her ud:

class myString
{
  private:
  char *theValue;
  int  theLength; // Inklusive ekstra '\x0'

  public:
  myString(int len);
  myString(void);

  char * getValue(void);
  int setValue(char *newValue);
};

myString::myString(int length)
{
  if (length > 0)
    theValue = new char(length+1);
  else
    theValue = NULL;
  theLength = length+1;
} // "Laveste" Constructor
mySTring::myString(void)
{
  myString(255);
} // Overloaded constructor.

myString::~myString()
{
  if (theLength > 0 && theValue != NULL)
    delete[] theValue;
 
  // Strengt taget ikke nødvendigt, da instansen af klassen jo forsvinder
  // når destructoren er kørt til ende, men jeg synes det ser pænt ud ...
  // og det forhindrer at ovenstående kan udføres to gange.
  theValue  = NULL;
  theLength = 0;
} // destructor

char * myString::getValue(void)
{
  return theValue;
} // getValue
int myString::setValue(char *s)
{
  int newLength = strlen(s) + 1;
  if (s > theLength)
  { // Gamle størrelse for lille til nye værdi - frigiv gamle storage
    // og allokér ny.
    delete[] theValue;
    theValue = new char(newLength);
  };
  memcpy(theValue, s, newLength);
} // setValue;
Avatar billede soepro Nybegynder
27. maj 2002 - 08:41 #4
og så skal ~myString() selvføgelig også være declareret under public:
Avatar billede it-dyret Nybegynder
27. maj 2002 - 12:17 #5
Min constructor og destructor ser således ud:

TreeNode::TreeNode(const TreeNode& node) {
  value = node.value;
  balance = node.balance;
  left = node.left;
  right = node.right;
}

TreeNode::~TreeNode(void) {
  if (left!=NULL) delete left;
  if (right!= NULL) delete right;
}
Avatar billede it-dyret Nybegynder
27. maj 2002 - 12:20 #6
Men selve kaldet: 'delete node' - er det det, som kalder destructoren eller skal man kalde destructoren implicit?!
Avatar billede it-dyret Nybegynder
27. maj 2002 - 12:22 #7
Det jeg hørte om overloading af new og delete var, at man kunne overloade metoden, så den kom med en udskrift, således man kunne følge med i allokering/deallokering...
Avatar billede soepro Nybegynder
27. maj 2002 - 13:08 #8
Din destructor er forkert - du laver ikke new på hverken left eller right i din constructor - og dermed skal du heller ikke lave delete af dem i destructoren. Det du gør ovenfor er at slette hele grene med alle "blade" i det øjeblik du sletter noden. Det er muligvis også det du ønsker, men normalt vil man balancere træet ud fra den slettede nodes 'forældre' og bevare linken til alle "bladene".

En nem måde at balancere på er at lave right til ny forældre på den slettede nodes plads, og så lade left være første "barn" under denne node. (Ved at bruge right som forældre, sikre du at træet altid er "tungest" til venstre.)

For at overloade new og delete skal du jo lave nye versioner for alle de klasser du ønsker at følge med i allokering/deallokering for - så synes jeg måske det var nemmere blot at ændre i deres constructor/deconstructor så de selv kalder din logging funktion, når det er relevant.
Avatar billede it-dyret Nybegynder
27. maj 2002 - 13:29 #9
så faktisk kan jeg nøjes med følgende destructor?!

TreeNode::~TreeNode(void) {
  left = NULL;
  right = NULL;
}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester