Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C++] twee keer destructor aangeroepen?

Pagina: 1
Acties:

  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Ik zit wat met c++ in VS.NET te rommelen en op de een of andere manier roept ie de destructor van mijn klasse twee keer aan. Daardoor loop het programma helemaal de soep in :(
De code is als volgt:
(aanroep)
code:
1
2
3
4
Vertex *v = new Vertex();
delete v;
Logger::append2Log("deleted");
v = NULL;

(in Vertex)
code:
1
2
3
4
5
6
7
8
9
10
11
Vertex::~Vertex( void )
{
    static bool beenHere = false;
    if( beenHere )
        Logger::append2Log( "upz");
    Logger::append2Log( "there");
    if( position )
        Logger::append2Log( "there1");
                //delete position;
    beenHere = true;
}


In mijn log krijg ik nu:
code:
1
2
3
4
5
there
upz
there
there1
deleted


Iemand een idee waardoor dit kan komen?

  • ^Mo^
  • Registratie: Januari 2001
  • Laatst online: 04-11 22:31
Wat gebeurd er in je constructor?

"There are 10 kinds of people in the world, those who understand binary and those who don't" | Werkbak specs


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

En je hebt het door een debugger gedraaid om te kijken waar precies die tweede call wordt gemaakt? (overigens is het gewoon ~Vertex() en niet ~Vertex(void))

(ik denk dat je ergens een temporary aanmaakt, en die dan uit scope gaat en destroyed wordt...)

Verwijderd

Ik denk (net als de anderen hier) dat we te weinig informatie hebben om je probleem op te lossen.

Probeer het probleem verder te localiseren (probeer het probleem te reproduceren in zo weinig mogelijk code), en er vervolgens met een debugger doorheen te lopen.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

als je, net voordat je een nieuwe Vertex aanmaakt, nou nog een regel in de log zet... komt die dan bovenaan of tussen "upz" en "there" in?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Waarschijnlijk een copy. Doe je ergens een pass-by-value?

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 05:14
Wat je dus wilt, is dat elke expliciete constructie precies 1 destructie met zich mee brengt. Een goede oplossing om dat te regelen, is om je constructors (dus ook de default 'lege' en copy constructors!) expliciet te maken. Als er nu ergens, ongewenst, een kopie optreedt, waarschuwt de compiler je hiervoor.

  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Ik ben er inmiddels achter wat het was. Mijn constructors waren zo:
code:
1
2
3
4
5
6
7
8
9
Vertex::Vertex( void )
{
    Vertex::Vertex( NULL );
}

Vertex::Vertex( double *position )
{
    this->position = position;
}


Helaas vond ie dat Vertex::Vertex(NULL) niet helemaal leuk. Daardoor werd automatisch de destructor aangeroepen tijdens de constructor. Als ik dat weg haal gaat het goed. Beetje jammer, want in Java mag dit wel. Is er een manier om deze truc in C++ toe te passen (zonder een aparte functie te schrijven)?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

je kunt gebruik maken van placing new, alleen of dat nou zo'n nette manier van programmeren is...

ben het idd met je eens dat C++ die functionaliteit mist, waardoor je dus of grote lappen code moet copypasten, of een private init () functie moet maken (ik kies meestal voor die laatste oplossing)

Maar in jouw geval kun je natuurlijk ook gewoon gebruik maken van een default parameter:

code:
1
2
3
4
Vertex::Vertex (double * pPosition = NULL)
{
    position = pPosition;
}

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Toch maar gebruik gemaakt van een init()-functie, maar eigenlijk een beetje jammer. Dat maakt de code erg lelijk. Maar ff voor de nieuwsgierigheid, wat is "placing new"?

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Het is "placement new" en dat zou ik zeer zeker niet gebruiken. Oisyn bedoeld dat met placement new je destructor niet automatisch wordt aangeroepen denk ik, maar dan nog zie ik niet echt het nut. Want dan werkt het nog steeds niet. Jouw Vertex::Vertex(NULL) doet ook helemaal niet wat jij denkt, er wordt een nieuw object gemaakt en destroyed op de stack, en de "position" in je object dat je met new aan hebt gemaakt blijft ongedefinieerd.
Meer info hier

Je kan het trouwens ook beter zo schrijven:

Vertex::Vertex(double* pPosition = NULL) : position(pPosition) {}

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Soultaker schreef op 15 augustus 2002 @ 19:59:
Wat je dus wilt, is dat elke expliciete constructie precies 1 destructie met zich mee brengt. Een goede oplossing om dat te regelen, is om je constructors (dus ook de default 'lege' en copy constructors!) expliciet te maken. Als er nu ergens, ongewenst, een kopie optreedt, waarschuwt de compiler je hiervoor.
En de betere is om elke ctor die je niet wilt private en undefined te maken.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
.oisyn schreef op 15 augustus 2002 @ 20:12:
je kunt gebruik maken van placement new, alleen of dat nou zo'n nette manier van programmeren is...
En of het werkt?
Denk eens aan exceptions vanuit de aangeroepen ctor, of wat er gebeurt met de vtable in het geval van [multiple][virtual] inheritance.

Kortom, zo'n geval van totdat iemand anders je code probeert.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Een explicit ctor gebruik je alleen als je niet wilt dat je compiler implicit type conversion doet. Maar dat zou je nog niet beschermen tegen deze fout hoor.
Wat je dus wilt, is dat elke expliciete constructie precies 1 destructie met zich mee brengt.
Dat lijkt me wel ja, anders heb je ofwel een leak, ofwel een crash ;) Hetzelfde geldt overigens voor implicit construction :P

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

dit werkt overigens ook

code:
1
2
3
4
Vector::Vector ()
{
    this->Vector::Vector (NULL);
}


(en maakt geen temporary aan ;)) :P

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
.oisyn schreef op 16 augustus 2002 @ 01:43:
dit werkt overigens ook

code:
1
2
3
4
Vector::Vector ()
{
    this->Vector::Vector (NULL);
}


(en maakt geen temporary aan ;)) :P
???
Ik kan dit niet parsen als een functie call. Het roept in elk geval geen tweede ctor aan voor dezelfde 'this' (modulo compiler bugs).

Het probleem heeft twee kanten, Vector::Vector is geen functienaam is, en die ctor is sowieso een 1-argument ctor terwijl je probeert zowel 'this' als 'NULL' mee te geven.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dit proggie:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class A
{
public:
    A ()
    {
        cout << __FUNCSIG__ << ": this = " << this << endl;
        this->A::A (3);
    }

    A (int)
    {
        cout << __FUNCSIG__ << ": this = " << this << endl;
    }

    ~A ()
    {
        cout << __FUNCSIG__ << ": this = " << this << endl;
    }
};

int main ()
{
    A a;

    return 0;
}


geeft de volgende output:
code:
1
2
3
__thiscall A::A(void): this = 0012FED7
__thiscall A::A(int): this = 0012FED7
__thiscall A::~A(void): this = 0012FED7


onder MSVC

(ik geloof dat ik er in gcc ook ooit eens mee gespeeld heb, maar dat weet ik niet zeker... het is een ((mis)?feature)|bug die ik heel lang geleden een keer ontdekt heb toen ik nog wat aan zat te rommelen :))
en die ctor is sowieso een 1-argument ctor terwijl je probeert zowel 'this' als 'NULL' mee te geven
er was ook nog een Vector::Vector (double *) weetjenog :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Er is natuurlijk niks ergers dan compiler bugs uit te buiten. Het is geen standaard code in ieder geval. MSVC compiled het idd ja (foei ;) ), en ook nog is zoals je zou verwachten. Comeau schreeuwt netjes meteen dat het niet mag :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

MSVC doet wel meer rare dingen ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1