On 4/6/20 2:45 PM, Nathan Sidwell wrote:
On 4/6/20 4:34 AM, Martin Liška wrote:


May I please ping Jason, Nathan and Jonathan who can help us here?

On IRC Martin clarified the question as essentially 'how do you pair up 
operator new and operator delete calls?' (so you may delete them if the object 
is not used).

I am not sure you're permitted to remove those calls in general.  All I can 
find is [expr.new]/12
'An implementation is allowed to omit a call to a replaceable global allocation 
function (17.6.2.1, 17.6.2.2). When it does so, the storage is instead provided 
by the implementation or provided by extending the allocation of another 
new-expression.'

But, I suspect the optimization is safe, in that either no one counts objects 
by their allocation, or if they do, they don't actually care that the 
std-conforming number of allocations happen.

The both operator new and operator delete are looked up in the same manner.  
The std does not require a 'matching pair' be found.  but it is extremely poor 
form for a class to declare exactly one of operator {new,delete}.

Hi.

Thank you for the information.


The following is well formed:

struct PoorForm {
   void *operator new (size_t s) {count++; return ::operator new (s)};
   static unsigned count;
};

Have you considered throwing ctors?

struct Obj {
   Obj (); // might throw
};

'obj = new Obj (); ... delete obj;' sequence expand to something like ...

// obj = new Obj ();
void *p = ::operator new (sizeof (Obj));
try {
   Obj::ctor(p);
}
catch (...) // cleanup code
{
   ::operator delete (p); // #1
   throw;
}

obj = (Obj*)p;

.... user code

// delete obj;
Obj::dtor (obj);
::operator delete (obj); // #2

calls 1 & 2 matchup to the operator new call

Looking at the throwing ctors:

$ cat new-delete2.C
#include <stdio.h>

struct A
{
  __attribute__((always_inline)) A(int x)
  {
    if (x == 123)
      throw x;
  }
};

int main(int argc, char **argv) {
  A *a = new A (argc);
  delete a;

  return 0;
}

$ g++-9 new-delete2.C -O2 -c -fdump-tree-optimized=/dev/stdout
...
  <bb 2> [local count: 1073741824]:
  _3 = operator new (1);
  if (argc_4(D) == 123)
    goto <bb 3>; [0.00%]
  else
    goto <bb 4>; [100.00%]

  <bb 3> [count: 0]:
  _8 = __cxa_allocate_exception (4);
  MEM[(int *)_8] = 123;
  __cxa_throw (_8, &_ZTIi, 0B);

  <bb 4> [local count: 1073741824]:
  operator delete (_3, 1);
  return 0;
...

As seen cddce can still optimize out
  _3 = operator new (1);
...
  operator delete (_3, 1);

Martin


Notice that para I quoted allows one to coalesce allocations using the global 
operator new/deletes.  The rules are pretty much as you can guess -- one 
lifetime must be entirely within the other.  If inner one's ctor throws, the 
exception path must destroy the outer.

does that help?

nathan


Reply via email to