Topic: placement operator delete


Author: "Andrei Alexandrescu (See Website For Email)" <SeeWebsiteForEmail@erdani.org>
Date: Tue, 21 Mar 2006 22:19:54 CST
Raw View
Consider the code:

struct T {
   void * operator new(size_t, void * p) {
     return p;
   }
   void operator delete(void *, size_t, void *) {
     ...
   }
};

So T's author implements the placement new as a member. Fine. Then, it
also implements sort of a delete counterpart, but one with three
parameters, not two. This is because T's implementer looked at 3.7.3.2
para 2 in the 1998 standard. That paragraph says that you can add size_t
as an optional second argument to the default deallocation function.

That suggests that void T::operator delete(void*, size_t, void*) is an
acceptable form of the placement delete operator. Unfortunately, I
couldn't find anything in the standard to clarify that, and 18.4.1.3
only mentions the global void ::operator delete(void*, void*).

Any clarification would be welcome. Thanks!


Andrei

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Anders Dalvander" <google@dalvander.com>
Date: Wed, 22 Mar 2006 21:15:24 CST
Raw View
Andrei Alexandrescu (See Website For Email) wrote:
> That suggests that void T::operator delete(void*, size_t, void*) is an
> acceptable form of the placement delete operator.

From: Bjarne Stroustrup's C++ Style and Technique FAQ
http://public.research.att.com/~bs/bs_faq2.html#placement-delete

Q: Is there a "placement delete"?
A: No but if you need one you can write your own. <snip>

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: krixel@qed.pl ("Krzysztof Zelechowski")
Date: Thu, 23 Mar 2006 02:59:46 GMT
Raw View
Uzytkownik "Andrei Alexandrescu (See Website For Email)"
<SeeWebsiteForEmail@erdani.org> napisal w wiadomosci
news:4420CA07.9030804@erdani.org...
> Consider the code:
>
> struct T {
>   void * operator new(size_t, void * p) {
>     return p;
>   }
>   void operator delete(void *, size_t, void *) {
>     ...
>   }
> };
>
> So T's author implements the placement new as a member. Fine. Then, it
> also implements sort of a delete counterpart, but one with three
> parameters, not two. This is because T's implementer looked at 3.7.3.2
> para 2 in the 1998 standard. That paragraph says that you can add size_t
> as an optional second argument to the default deallocation function.
>
> That suggests that void T::operator delete(void*, size_t, void*) is an
> acceptable form of the placement delete operator. Unfortunately, I
> couldn't find anything in the standard to clarify that, and 18.4.1.3 only
> mentions the global void ::operator delete(void*, void*).
>
> Any clarification would be welcome. Thanks!
>

It may actually be much worse IIRC.  Consider a class with both placement
new and ordinary new declared:

class T { public: static void *operator new(size_t), operator new(size_t,
size_t); static void *operator delete(void *, size_t); };

Can T::operator delete(void *, size_t) serve both as ordinary delete and
unwinding delete?

Chris


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: SeeWebsiteForEmail@erdani.org ("Andrei Alexandrescu (See Website For Email)")
Date: Thu, 23 Mar 2006 07:01:38 GMT
Raw View
Anders Dalvander wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>
>>That suggests that void T::operator delete(void*, size_t, void*) is an
>>acceptable form of the placement delete operator.
>
>
> From: Bjarne Stroustrup's C++ Style and Technique FAQ
> http://public.research.att.com/~bs/bs_faq2.html#placement-delete
>
> Q: Is there a "placement delete"?
> A: No but if you need one you can write your own. <snip>

Thanks for the link. Unfortunately, it doesn't address my question,
which refers to the ambiguity of the second size_t parameter that
T::operator delete might define.


Andrei

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Thu, 23 Mar 2006 10:32:02 CST
Raw View
Andrei Alexandrescu (See Website For Email) wrote:
> Consider the code:
>
> struct T {
>    void * operator new(size_t, void * p) {
>      return p;
>    }
>    void operator delete(void *, size_t, void *) {
>      ...
>    }
> };
>
> So T's author implements the placement new as a member. Fine. Then, it
> also implements sort of a delete counterpart, but one with three
> parameters, not two. This is because T's implementer looked at 3.7.3.2
> para 2 in the 1998 standard. That paragraph says that you can add size_t
> as an optional second argument to the default deallocation function.
>
> That suggests that void T::operator delete(void*, size_t, void*) is an
> acceptable form of the placement delete operator.

I don't see how you reached that conclusion. Section 3.7.3.2 says that
operator delete() must have a first parameter of type void*, and that
it can be declared with more than one parameter. It says several
important things about operator delete() when it is declared with
exactly one parameter, and when it is declared with exactly two
parameters if the second one is size_t. However, it says absolutely
nothing about operator delete() when declared with any other number of
parameters.

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Andrei Polushin" <polushin@gmail.com>
Date: Thu, 23 Mar 2006 18:46:16 CST
Raw View
There is nothing in [3.7.3.2/2], that describes placement forms of
(de)allocation function. Instead, it describes two additional forms of
non-placement deallocation functions. For placement forms, [5.3.4/19]
should be used.

>From the beginning:

1. Deallocation function with three or more parameters is "unusual" or
"placement form" (3.7.3.2/2), and there is no syntax to call such
function explicitly (5.3.5/1).

2. It can be called, however, as a result of new-expression (5.3.4/1),
which throws an exception (5.3.4/8) from the object initialization
(5.3.4/17).

3. A matching deallocation function should have the same number of
parameters and all parameter types except the first are identical
(5.3.4/19).

4. If there is no matching deallocation function defined, this might
result in memory leak (see note to 5.3.4/17 and 5.3.4/19 again).

5. If there is no matching allocation function defined, then the
deallocation function cannot be called at all, such deallocation
function is unused. It can be made useful if we will define its
matching allocation function (probably in derived class).

To correct your example, there should be two matching pairs:

struct T {
  // new(p) T();
  void *  operator new(size_t, void * p);
  void operator delete(void *, void * p);

  // new(sz, p) T();
  void *  operator new(size_t, size_t sz, void * p);
  void operator delete(void *, size_t sz, void * p);
};

If you'll omit the first operator delete, this might lead to memory
leak. If you'll omit the second operator new, that will make the
second operator delete useless.

Hope this helps.

--
Andrei Polushin

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: SeeWebsiteForEmail@erdani.org ("Andrei Alexandrescu (See Website For Email)")
Date: Fri, 24 Mar 2006 06:13:06 GMT
Raw View
Andrei Polushin wrote:
[snip]
> To correct your example, there should be two matching pairs:
>
> struct T {
>   // new(p) T();
>   void *  operator new(size_t, void * p);
>   void operator delete(void *, void * p);
>
>   // new(sz, p) T();
>   void *  operator new(size_t, size_t sz, void * p);
>   void operator delete(void *, size_t sz, void * p);
> };
>
> If you'll omit the first operator delete, this might lead to memory
> leak. If you'll omit the second operator new, that will make the
> second operator delete useless.
>
> Hope this helps.

Thanks. So at the end of the day, I can't have access to the size of the
object being deleted in any placement operator delete! Quite bizarre.

Andrei

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: non-existent@iobox.com ("Sergey P. Derevyago")
Date: Fri, 24 Mar 2006 16:06:13 GMT
Raw View
"Andrei Alexandrescu (See Website For Email)" wrote:
> Thanks. So at the end of the day, I can't have access to the size of the
> object being deleted in any placement operator delete! Quite bizarre.
>
 Yes, you can.
 The trick works as expected but can be considered to be non-conforming (BTW
can't it?).

template <class T>
struct sh_ptr_core {
       mem_pool& pool;
       T* ptr;
       int refs;

       sh_ptr_core(mem_pool& mp, T* p) : pool(mp), ptr(p), refs(1) {}
       ~sh_ptr_core() { delete ptr; }

       void* operator new(size_t size, mem_pool& mp)
       {
        return mp.allocate(size);
       }

#ifndef DERS_NO__PLACEMENT_DELETE
       void operator delete(void* ptr, size_t size, mem_pool& mp)
       {
        mp.deallocate(ptr, size);
       }
#endif

       void operator delete(void* ptr, size_t size)
       {
        sh_ptr_core* this_=static_cast<sh_ptr_core*>(ptr);  // <===== !
        this_->pool.deallocate(ptr, size);
       }
};

The trick is
        sh_ptr_core* this_=static_cast<sh_ptr_core*>(ptr);
conversion. Here I suppose that ~sh_ptr_core() dtor doesn't invalidate its
pool reference.
 Really, an implementation that corrupts the object memory right after the
dtor call has finished but just before the operator delete() gets called can
be considered to impose additional run-time overhead. So it's not likely to be
met in real life.
--
         With all respect, Sergey.               http://ders.angen.net/
         mailto : ders at skeptik.net

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]