Topic: Matching class new and delete (long)


Author: "Jonathan H Lundquist" <fluxsmith@fluxsmith.com>
Date: 1999/03/19
Raw View
I think you are correct.  Thank you for the citation.  I had not found that
previously because it is so far-flung from 3.7.3.2.  Accordingly, I think
for once MSVC's behavior is 'standard', and the como behavior document by
Mr. Naran is non-standard.  However, my main point in this thread is that
while the behavior I documented for MSVC may be standard, I don't think it's
correct.  I think como's handling of the problem is superior, though still
not ideal.
Repeating an earlier statement, I think the standard needs language to the
effect:

"In the absence of the single parameter 'usual' operator delete, the
signature for the 'usual' operator delete shall be void operator
delete(void* p, size_t size), and the signature for any placement operator
delete shall have placement parameters following these two 'usual'
parameters"

Thereby allowing the matching Mr. Naran proposed.  However, I do not know
how to propose such a change or to formally assert a defect.  I would hope
discussion in this group is sufficient to bring a matter to the attention of
interested committee members.  I am actually surprised how little interest
this thread generated.

Doug Harrison <dHarrison@worldnet.att.net> wrote in message
news:36f20663.15201609@netnews.worldnet.att.net...
>
>Siemel Naran wrote:
>
>>Yes, I think that a call to
>>   operator new(size_t,A,B,C,D);
>>should be matched with a call to
>>   operator delete(void*,size_t,A,B,C,D);
>
>I think the standard prohibits this. See 5.3.4/19-20.
>



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@localhost.localdomain.COM (Siemel Naran)
Date: 1999/03/14
Raw View
On 14 Mar 1999 00:44:28 GMT, Jonathan H Lundquist

>Well, it seems your compiler definitely does a better job in preventing
>allocation leaks, but you still don't get a reliable size passed to operator
>delete in the presence of placement new and an exception thrown from the
>constructor.  I think the standard *should* say something to the effect of:

Yes, I think that a call to
   operator new(size_t,A,B,C,D);
should be matched with a call to
   operator delete(void*,size_t,A,B,C,D);

But to enforce this, a compiler must require that if we define a
   class::operator new(size_t,A,B,C,D);
then we must also define a
   class::operator delete(void*,size_t,A,B,C,D);
I don't think the standard has such a requirement.


>"In the absence of the single parameter 'usual' operator delete, the
>signature for the 'usual' operator delete shall be void operator
>delete(void* p, size_t size), and the signature for any placement operator
>delete shall have placement parameters following these two 'usual'
>parameters."

Fine.

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Joerg Schaible" <Joerg.Schaible@no-spam.gft.de>
Date: 1999/03/16
Raw View
Hi Siemel, hi Jonathan,

your thread is very interesting to me, since I had the same problems hacking
last night and did not found any definition in my documentation.

>But to enforce this, a compiler must require that if we define a
>   class::operator new(size_t,A,B,C,D);
>then we must also define a
>   class::operator delete(void*,size_t,A,B,C,D);
>I don't think the standard has such a requirement.

The MSVC6 gives a warning if the placement delete is missing, but will call
the default operator delete :-(

J   rg

--
BTW: It is normally better to answer to the group! For direct mail reply
remove "no_spam."
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Jonathan H Lundquist" <fluxsmith@fluxsmith.com>
Date: 1999/03/12
Raw View
While trying to answer someone else's question on this topic, I discovered
my compiler (MSVC) does not work as I expected.  I'm prepared to believe
it's yet another bug in MSVC, I've found plenty, but I can't find any
information in the standard regarding the correct behavior.  And, if the
behavior uncovered below is standard, then I wonder if there's been any
serious consideration that it's a bug in the standard.  Any enlightenment
would be appreciated.

Exposition:
S1 and S2 provide operator new, and an operator delete which the standard
refers to as a 'usual' deallocation function (3.7.3.2/2).  Everything works
as one would hope.

In S3 and S4, we wish to receive the size as a parameter to delete.  The
same section (3.7.3.2/2) says that in the absence of the single parameter
delete, this is also a 'usual' deallocation function.  In the case of S3,
the results are as desired.  However, S4 throws an exception from it's
constructor.  In this case MSVC doesn't consider the two parameter version a
match for the operator new, and the allocation leaks.  I think this is
undesirable behavior, but if the standard forbids it, I can't find the
citation.

S5 and S6 provide only a placement new, and the two parameter 'usual'
delete.  In the case of S5, delete is called with the size for the deletion.
In the case of S6 which throws from its destructor, delete is called with
the placement value.  I also think this asymmetry is undesirable.

S7 and S8 are based on the slim hope that if the two parameter delete can be
considered the 'usual' delete, the three parameter version can be considered
the placement delete.  However, when the exception is thrown from the
constructor of S8, the compiler again considers the two parameter one a
match for the placement new.  And finds no match for the usual new, so again
an allocation leaks.



Author: sbnaran@localhost.localdomain (Siemel Naran)
Date: 1999/03/13
Raw View
On 12 Mar 1999 13:42:43 GMT, Jonathan H Lundquist

>Exposition:
>S1 and S2 provide operator new, and an operator delete which the standard
>refers to as a 'usual' deallocation function (3.7.3.2/2).  Everything works
>as one would hope.

// your output
S1::operator new(size_t size = 4)
S1::operator delete(void*)
S2::operator new(size_t size = 4)
S2::operator delete(void*)

// my output (using como) -- same as yours
S1::operator new(size_t size = 4)
S1::operator delete(void*)
S2::operator new(size_t size = 4)
S2::operator delete(void*)



>In S3 and S4, we wish to receive the size as a parameter to delete.  The
>same section (3.7.3.2/2) says that in the absence of the single parameter
>delete, this is also a 'usual' deallocation function.  In the case of S3,
>the results are as desired.  However, S4 throws an exception from it's
>constructor.  In this case MSVC doesn't consider the two parameter version a
>match for the operator new, and the allocation leaks.  I think this is
>undesirable behavior, but if the standard forbids it, I can't find the
>citation.

// your output -- missing call to S4::operator delete(void*,size_t)
S3::operator new(size_t size = 4)
S3::operator delete(void*, size_t n = 4)
S4::operator new(size_t size = 4)

// my output -- has the call to S4::operator delete(void*,size_t)
S3::operator new(size_t size = 4)
S3::operator delete(void*, size_t n = 4)
S4::operator new(size_t size = 4)
S4::operator delete(void*, size_t n = 4)


>S5 and S6 provide only a placement new, and the two parameter 'usual'
>delete.  In the case of S5, delete is called with the size for the deletion.
>In the case of S6 which throws from its destructor, delete is called with
>the placement value.  I also think this asymmetry is undesirable.

// typo
// above you write, "case of S6 which throws from its destructor"
// but your actual code throws from the constructor

// your output
S5::operator new(size_t size = 4, size_t n = 0)
S5::operator delete(void*, size_t n = 4)
S6::operator new(size_t size = 4, size_t n = 0)
S6::operator delete(void*, size_t n = 0)

// my output -- same as yours
S5::operator new(size_t size = 4, size_t n = 0)
S5::operator delete(void*, size_t n = 4)
S6::operator new(size_t size = 4, size_t n = 0)
S6::operator delete(void*, size_t n = 0)

// my comments
// seems that you should have a compile error
// because you've declared a placement operator new
// but not a corresponding placement operator delete
// assuming that there should be no error,
// it seems that the last line should be
// S6::operator delete(void*, size_t n = 4)
// because 4 bytes are being deleted


>S7 and S8 are based on the slim hope that if the two parameter delete can be
>considered the 'usual' delete, the three parameter version can be considered
>the placement delete.  However, when the exception is thrown from the
>constructor of S8, the compiler again considers the two parameter one a
>match for the placement new.  And finds no match for the usual new, so again
>an allocation leaks.

// your output
S7::operator new(size_t size = 4)
S7::operator delete(void*, size_t size = 4)
S7::operator new(size_t size = 4, size_t n = 0)
S7::operator delete(void*, size_t size = 4)

// my output -- same as yours
S7::operator new(size_t size = 4)
S7::operator delete(void*, size_t size = 4)
S7::operator new(size_t size = 4, size_t n = 0)
S7::operator delete(void*, size_t size = 4)

// my comments
// seems like the last line should be
// S7::operator delete(void*, size_t size = 4, size_t n = 0)
// ie: placement new matched with placement delete

// your output
S8::operator new(size_t size = 4)
S8::operator new(size_t size = 4, size_t n = 0)

// my output
S8::operator new(size_t size = 4)
S8::operator delete(void*, size_t size = 4)
S8::operator new(size_t size = 4, size_t n = 0)
S8::operator delete(void*, size_t size = 0)

// my comments
// at least como calls some operator delete
// but once again, I think the last line should be
// S8::operator delete(void*, size_t size = 4, size_t n = 0)
// but overloading operator new and operator placement new
// seems to be a strange thing to do


>From these events I conclude; I can have either the size information in
>delete, or I can have correct placement resolution in the event of
>exceptions thrown from destructors, but I can't have both.

Hmmm.

Below, you should also do
   #include <stdlib.h> /* malloc, free */



>// Test code:
>
>#include <iostream>
>
>struct S1 {
>   void* operator new(size_t size)
>   {
>      std::cout << "S1::operator new(size_t size = " << size << ")" <<
>std::endl;
>      return malloc(size);
>   }
>
>   void operator delete(void* p)
>   {
>      std::cout << "S1::operator delete(void*)" << std::endl;
>      free(p);
>   }
>
>   int i;
>};
>
>struct S2 {
>   S2()
>   {
>      throw 0;
>   }
>
>   void* operator new(size_t size)
>   {
>      std::cout << "S2::operator new(size_t size = " << size << ")" <<
>std::endl;
>      return malloc(size);
>   }
>
>   void operator delete(void* p)
>   {
>      std::cout << "S2::operator delete(void*)" << std::endl;
>      free(p);
>   }
>
>   int i;
>};
>
>struct S3 {
>   void* operator new(size_t size)
>   {
>      std::cout << "S3::operator new(size_t size = " << size << ")" <<
>std::endl;
>      return malloc(size);
>   }
>
>   void operator delete(void* p, size_t n)
>   {
>      std::cout << "S3::operator delete(void*, size_t n = " << n << ")" <<
>std::endl;
>      free(p);
>   }
>
>   int i;
>};
>
>struct S4 {
>   S4()
>   {
>      throw 0;
>   }
>
>   void* operator new(size_t size)
>   {
>      std::cout << "S4::operator new(size_t size = " << size << ")" <<
>std::endl;
>      return malloc(size);
>   }
>
>   void operator delete(void* p, size_t n)
>   {
>      std::cout << "S4::operator delete(void*, size_t n = " << n << ")" <<
>std::endl;
>      free(p);
>   }
>
>   int i;
>};
>
>struct S5 {
>   void* operator new(size_t size, size_t n)
>   {
>      std::cout << "S5::operator new(size_t size = " << size
>                << ", size_t n = " << n << ")" << std::endl;
>      return malloc(size);
>   }
>
>   void operator delete(void* p, size_t n)
>   {
>      std::cout << "S5::operator delete(void*, size_t n = " << n << ")" <<
>std::endl;
>      free(p);
>   }
>
>   int i;
>};
>
>struct S6 {
>   S6()
>   {
>      throw 0;
>   }
>
>   void* operator new(size_t size, size_t n)
>   {
>      std::cout << "S6::operator new(size_t size = " << size
>                << ", size_t n = " << n << ")" << std::endl;
>      return malloc(size);
>   }
>
>   void operator delete(void* p, size_t n)
>   {
>      std::cout << "S6::operator delete(void*, size_t n = " << n << ")" <<
>std::endl;
>      free(p);
>   }
>
>   int i;
>};
>
>struct S7 {
>   void* operator new(size_t size)
>   {
>      std::cout << "S7::operator new(size_t size = " << size << ")" <<
>std::endl;
>      return malloc(size);
>   }
>
>   void* operator new(size_t size, size_t n)
>   {
>      std::cout << "S7::operator new(size_t size = " << size
>                << ", size_t n = " << n << ")" << std::endl;
>      return malloc(size);
>   }
>
>   void operator delete(void* p, size_t size)
>   {
>      std::cout << "S7::operator delete(void*, size_t size = " << size <<
>")" << std::endl;
>      free(p);
>   }
>
>   void operator delete(void* p, size_t size, size_t n)
>   {
>      std::cout << "S7::operator delete(void*, size_t size = " << size
>                << ", size_t n = " << n << ")" << std::endl;
>   }
>
>   int i;
>};
>
>struct S8 {
>   S8()
>   {
>      throw 0;
>   }
>
>   void* operator new(size_t size)
>   {
>      std::cout << "S8::operator new(size_t size = " << size << ")" <<
>std::endl;
>      return malloc(size);
>   }
>
>   void* operator new(size_t size, size_t n)
>   {
>      std::cout << "S8::operator new(size_t size = " << size
>                << ", size_t n = " << n << ")" << std::endl;
>      return malloc(size);
>   }
>
>   void operator delete(void* p, size_t size)
>   {
>      std::cout << "S8::operator delete(void*, size_t size = " << size <<
>")" << std::endl;
>      free(p);
>   }
>
>   void operator delete(void* p, size_t size, size_t n)
>   {
>      std::cout << "S8::operator delete(void*, size_t size = " << size
>                << ", size_t n = " << n << ")" << std::endl;
>   }
>
>   int i;
>};
>
>int main()
>{
>   S1* ps1 = new S1;
>   delete ps1;
>
>   try {
>      S2* ps2 = new S2;
>   }
>   catch(...) {
>   }
>
>   S3* ps3 = new S3;
>   delete ps3;
>
>   try {
>      S4* ps4 = new S4;
>   }
>   catch(...) {
>   }
>
>   S5* ps5 = new(0) S5;
>   delete ps5;
>
>   try {
>      S6* ps6 = new(0) S6;
>   }
>   catch(...) {
>   }
>
>   S7* ps7a = new S7;
>   delete ps7a;
>
>   S7* ps7b = new(0) S7;
>   delete ps7b;
>
>   try {
>      S8* ps8a = new S8;
>   }
>   catch(...) {
>   }
>
>   try {
>      S8* ps8b = new(0) S8;
>   }
>   catch(...) {
>   }
>
>   return 0;
>}


--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Jonathan H Lundquist" <fluxsmith@fluxsmith.com>
Date: 1999/03/14
Raw View
Well, it seems your compiler definitely does a better job in preventing
allocation leaks, but you still don't get a reliable size passed to operator
delete in the presence of placement new and an exception thrown from the
constructor.  I think the standard *should* say something to the effect of:

"In the absence of the single parameter 'usual' operator delete, the
signature for the 'usual' operator delete shall be void operator
delete(void* p, size_t size), and the signature for any placement operator
delete shall have placement parameters following these two 'usual'
parameters."

However, I can find no such language specifying how the 'usual' two
parameter delete and placement delete signatures interact.  If I'm correct,
then I suspect we all have a slim chance of getting the appropriate compiler
behavior until the standard is updated accordingly.

Siemel Naran <sbnaran@localhost.localdomain> wrote in message
news:slrn7eiep1.nv5.sbnaran@localhost.localdomain...
>On 12 Mar 1999 13:42:43 GMT, Jonathan H Lundquist
>
>// my output (using como)
>S5::operator new(size_t size = 4, size_t n = 0)
>S5::operator delete(void*, size_t n = 4)
>S6::operator new(size_t size = 4, size_t n = 0)
>S6::operator delete(void*, size_t n = 0)
>
>// my output -- same as yours
>S7::operator new(size_t size = 4)
>S7::operator delete(void*, size_t size = 4)
>S7::operator new(size_t size = 4, size_t n = 0)
>S7::operator delete(void*, size_t size = 4)
>
>// my comments
>// seems like the last line should be
>// S7::operator delete(void*, size_t size = 4, size_t n = 0)
>// ie: placement new matched with placement delete
>
>// my output
>S8::operator new(size_t size = 4)
>S8::operator delete(void*, size_t size = 4)
>S8::operator new(size_t size = 4, size_t n = 0)
>S8::operator delete(void*, size_t size = 0)
>
>// my comments
>// at least como calls some operator delete
>// but once again, I think the last line should be
>// S8::operator delete(void*, size_t size = 4, size_t n = 0)
>// but overloading operator new and operator placement new
>// seems to be a strange thing to do
>
>>From these events I conclude; I can have either the size information in
>>delete, or I can have correct placement resolution in the event of
>>exceptions thrown from destructors, but I can't have both.
>
>Hmmm.
>





[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]