Jump to page: 1 2
Thread overview
When destructors are called
Oct 03, 2007
DQNOK
Oct 10, 2007
Walter Bright
Oct 16, 2007
Heinz Saathoff
Oct 16, 2007
DQNOK
Oct 17, 2007
Heinz Saathoff
Re: When destructors are called: Thanks Heinz
Oct 17, 2007
DQNOK
Re: When destructors are called:
Oct 17, 2007
DQNOK
Oct 18, 2007
Heinz Saathoff
Oct 18, 2007
Heinz Saathoff
Oct 18, 2007
Heinz Saathoff
Re: When destructors are called: Possible error in DMC???
Oct 22, 2007
DQNOK
Nov 01, 2007
Heinz Saathoff
Nov 02, 2007
DQNOK
Nov 15, 2007
mikeb
Oct 17, 2007
DQNOK
Oct 18, 2007
Heinz Saathoff
Oct 22, 2007
DQNOK
October 03, 2007
I though destructors HAD TO BE CALLED when an object went out of scope.  I realize that as long as the object is in scope, when the destructor is called is implementation dependent.  (Well, I suppose that is still standard C++ behavior).

I have code that really needs the destructor called when I want it called.  I've tried

{ // create a new scope here
   printf( "%s", (char*)mytype(&x) ); //creates a mytype temporary
} // end the scope here to force mytype::~mytype on the temporary
//shouldn't be necessary because the temporary is out of scope
//immediately after the printf call.

but it's not working.  The destructor is not being called until the end of the function.  The mytype constructor alters x (inserts a null terminator for use with Standard C library functions), then the destructor puts it back to the way it was (removes the null terminator).  Since the destructor is not be called immediately, x is being left altered and unuseable until after the function exits.

Visual C++ calls the destructor immediately, and all is good. Digital Mars C++ waits to call the destructor and all is not good.

Is this conforming behavior?  Is there a way to force a destructor call?

Thanks
David
October 10, 2007
If you could boil this down to a small test case, I'd appreciate it.
October 16, 2007
DQNOK wrote...
> I have code that really needs the destructor called when I want it called.  I've tried
> 
> { // create a new scope here
>    printf( "%s", (char*)mytype(&x) ); //creates a mytype temporary
> } // end the scope here to force mytype::~mytype on the temporary
> //shouldn't be necessary because the temporary is out of scope
> //immediately after the printf call.

I'm not sure if the code is valid. You create a temporary 'mytype' and
cast this object to a char*. Note that constructors don't return a
value.
I tried a small example with the cast an got this message:
  printf("my_type modified: %s\n", (char*)mytype(my_str));
                                                        ^
  a.cpp(19) : Error: illegal cast
  from: mytype
  to  : char *

> but it's not working.  The destructor is not being called until the end of the function.

Without the cast this works (but is still not portable):
   #include <stdio.h>

   struct mytype
   {
       mytype(char *s) : str(s)
       {
           prev_char = str[0]; str[0] = 'A';
       }
       ~mytype() {str[0] = prev_char;}

       char *str;
       char prev_char;
   };//mytype

   int main()
   {
     char my_str[] = "  new way to do it";
     printf("my_type modified: %s\n", mytype(my_str));
     printf("old again: %s\n", my_str);
     return 0;
   }

This example relies on object layout and is therefore not portable.


- Heinz
October 16, 2007
== Quote from Heinz Saathoff (newshsaat@arcor.de)'s article
> DQNOK wrote...
> > I have code that really needs the destructor called when I
want it
> > called.  I've tried
> >
> > { // create a new scope here
> >    printf( "%s", (char*)mytype(&x) ); //creates a mytype
temporary
> > } // end the scope here to force mytype::~mytype on the
temporary
> > //shouldn't be necessary because the temporary is out of scope //immediately after the printf call.
> I'm not sure if the code is valid.

It compiles and runs under both DMC, and VC, without any
warnings.  Under VC (using the debugger to track thru it) the
destructor on the temporary is called immediately when it goes out
of scope (right after printf is through with it).  Under DMC, the
temporary's destructor is not called until the end of the (main())
function.

>You create a temporary 'mytype' and
> cast this object to a char*.
I have overloaded the operator char*() and operator const char*()
to return the correct character pointer member of mytype.  It
works fine.


> This example relies on object layout and is therefore not
portable.
> - Heinz
I'm not relying on object layout; I specify the "cptr" member when casting.  Apparently it's still not portable anyway because I'm relying on the destructor to be called in a deterministic way.

Thank you Heinz for your thoughts and response.
October 17, 2007
Hello,


DQNOK wrote...
> 
> >You create a temporary 'mytype' and
> > cast this object to a char*.
> I have overloaded the operator char*() and operator const char*()
> to return the correct character pointer member of mytype.  It
> works fine.

Ok, didn't know this.

> > This example relies on object layout and is therefore not
> portable.
> > - Heinz
> I'm not relying on object layout; I specify the "cptr" member when casting.  Apparently it's still not portable anyway because I'm relying on the destructor to be called in a deterministic way.

As far as I know the actual standard is more precise in when the destructor must be called. I've added the operator char*() to may program and it runs with dmc (scppn version is 8.48.10n). This is the test prog:

   #include <stdio.h>

   struct mytype
   {
       mytype(char *s) : str(s)
       {
           prev_char = str[0]; str[0] = 'A';
       }
       ~mytype() {str[0] = prev_char;}

       operator char* () { return str; }

       char prev_char;
       char *str;
   };//mytype

   int main()
   {
     char my_str[] = "  new way to do it";
     printf("my_type modified: %s\n", (char*)mytype(my_str));
     printf("old again: %s\n", my_str);
     return 0;
   }



> Thank you Heinz for your thoughts and response.


- Heinz
October 17, 2007
> As far as I know the actual standard is more precise in when the destructor must be called.

I don't know what the standard says.  Where can I find it (short
of purchasing it from ISO or ANSI).

> I've added the operator char*() to may program and it runs with
> dmc (scppn version is 8.48.10n).

Great!  Looks like maybe I just need to upgrade.  I'm still running 8.42.

Thanks again, Heinz.
David
October 17, 2007
> > I've added the operator char*() to may program and it runs with
> > dmc (scppn version is 8.48.10n).
> Great!  Looks like maybe I just need to upgrade.  I'm still running 8.42.

I just now downloaded the latest 8.5 (scppn 8.50.4n), and am still getting the earlier behavior of the destructor not being called until the function exits.

Guess maybe I'll try to whittle my class down until it behaves like Heinz's class does, and discern what code makes it behave the way it currently is...

Or maybe I'm just barking up the wrong tree!  If C++ is free (by
the standard) to call destructors when it pleases, then I just
need to either:
 - redesign my code
 - or use a different compiler, and hope they don't choose to
alter its destructor-call behavior.

BTW, when I type "dmc ", the compiler still reports itself as version 8.42n even though scppn is 8.50.4n

David
October 17, 2007
== Quote from Heinz Saathoff (newshsaat@arcor.de)'s article
> DQNOK wrote...
> > I have code that really needs the destructor called when I
want it
> > called.  I've tried
> >
> > { // create a new scope here
> >    printf( "%s", (char*)mytype(&x) ); //creates a mytype
temporary
> > } // end the scope here to force mytype::~mytype on the
temporary
> > //shouldn't be necessary because the temporary is out of scope //immediately after the printf call.


>    #include <stdio.h>
>    struct mytype
>    {
>        mytype(char *s) : str(s)
>        {
>            prev_char = str[0]; str[0] = 'A';
>        }
>        ~mytype() {str[0] = prev_char;}
>        char *str;
>        char prev_char;
>    };//mytype
>    int main()
>    {
>      char my_str[] = "  new way to do it";
>      printf("my_type modified: %s\n", mytype(my_str));
>      printf("old again: %s\n", my_str);
>      return 0;
>    }
> - Heinz

Heinz: I reworked your code a little to make it more reflective of my actual code.  I've attached it but don't know if it'll come thru since I've never used attachments before.

Surprisingly, it works as expected; the destructors are called when I think they should be called; just like in your code.  Also very surprising is that there are NO CALLS TO THE COPY CONSTRUCTOR.  I thought that when an object was passed as a function parameter (like to printf), the copy constructor was always called!  ALWAYS CALLED!  Therefore, to make things work correctly, my original copy constructor alerted the copy that it was in fact, a copy; a hack I needed to prevent the copy from misbehaving when it got destroyed.  I'm thinking THIS may be the actual source of my mis-behaving code, not that the destructor is not being called.

Is the compiler permitted to optimize away a copy-constructor call???

David
October 18, 2007
Hello,

DQNOK wrote...
> 
> BTW, when I type "dmc ", the compiler still reports itself as version 8.42n even though scppn is 8.50.4n

dmc is only a 'driver program' that invokes the real compiler, optimizer, linker. scppn displays the version number of the real compiler.


- Heinz
October 18, 2007
Hello again,

DQNOK wrote...
> Or maybe I'm just barking up the wrong tree!  If C++ is free (by
> the standard) to call destructors when it pleases, then I just
> need to either:
>  - redesign my code
>  - or use a different compiler, and hope they don't choose to
> alter its destructor-call behavior.

I just looked what the standard says abaut temporaries (12.2):
  "A temporary bound to a reference type parameter
   in a function call persists until the completion
   of the full expression containing the call."

In your example it's not the temporary object but a returned value of a member function (operators are also meber functions). The full expression is the function call. So the destructor shall be called at the end of the function and before the next one is called, just as my example does.



- Heinz
« First   ‹ Prev
1 2