• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 520
  • Last Modified:

Placement new queries

Ah hello.

Firstly, seasons greetings to one and all!

Now, please consider the following code, from http://www.glenmccl.com/nd_cmp.htm

      int flag = 0;

        typedef unsigned int size_t;

        void operator delete(void* p, int i)
        {
                flag = 1;
        }

        void* operator new(size_t s, int i)
        {
                return new char[s];
        }

        class A {
        public:
                A() {throw -37;}
        };

        int main()
        {
                try {
                        A* p = new (1234) A;
                }
                catch (int i) {
                }
                if (flag == 0)
                        return 1;
                else
                        return 0;
        }

Now, at the very bottom of the article, we have "Note also that you can't call overloaded operator delete directly via the operator syntax; you'd have to code it as a regular function call.".

OK.  So, if I ammend the code above, so the first thing before the try/catch block is

      int* n = new ( 100 ) int;
      //operator delete ( n, 100 );
      delete n;

1) I find that the normal delete call works fine; that being the case, what is the statement shown above all about??

2) The first lot of code shown above does not have anything that actually does the freeing of memory, we just set flag to be 1.  So am I correct in thinking that I should ammend this to be

        void operator delete(void* p, int i)
        {
            free ( p );      // NEW LINE!
                flag = 1;
        }

Or should I use delete?  Which is correct?  I have noted that delete calls into free() anyway, but as the rule goes we should always use new/delete and malloc/free etc...

TIA
0
mrwad99
Asked:
mrwad99
  • 12
  • 6
2 Solutions
 
evilrixSenior Software Engineer (Avast)Commented:
With placement new you normally allocate a memory buffer (however you wish) and then pass the address of that buffer to new

char buf[10];
A * pa = new(buf) A;

It then uses the memory buffer you've supplied.

You don't call delete on this, you call the destructor of A directly.
pa->~A();

There are quite a few caveats to be aware of when using placement new, including explicit handing of exceptions throw in constructors to avoid memory leaks.

http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10

The code example you provide shows an example of how to overload operator placement new to provide a more specialised allocation strategy. A bit like providing a specialised allocator for an STL container.

1. When you say it works fine do you mean it calls the operator placement delete?

2. Probably, although it should call delete [] p not free(p)

>>I have noted that delete calls into free() anyway
It doesn't have to at all

>> but as the rule goes we should always use new/delete and malloc/free etc...
always match correctly, as you say here
0
 
evilrixSenior Software Engineer (Avast)Commented:
This is interesting...

http://www.devx.com/tips/Tip/13612
0
 
evilrixSenior Software Engineer (Avast)Commented:
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
mrwad99Author Commented:
RX!  Thanks for the comment.

1).  OK.  When I execute this code:

int* n = new ( 100 ) int;
delete n;

the first thing that gets called is my custom new() operator, which allocates a new char array.  Then, I step into the delete call and I get

void operator delete(void *pUserData )

within dbgdel.cpp (using VS2008) called.

2) OK, I take it that is because I allocate using new[] in my operator new?

>> It doesn't have to at all...

What do you mean here?  Do some implementations differ?

>>
char buf[10];
A * pa = new(buf) A;

3) Heh, much better example, ta :)  I take it here that we never need a matching 'delete' to automatically clean up if an exception is thrown, because the memory is allocated on the stack?

Since you seem to know what you are talking about with this, I read

4) "Placement new is also faster because the construction of an object on a preallocated buffer takes less time."

but I don't see how this can be true, surely all we are doing is breaking the creation process up into two distinct steps (allocate memory then create object) as opposed to doing both at once?

5) Finally, can you state a place where this would be a crucial technique to use?  I don't see how it is more efficient than letting the system allocate memory; if we tidy it up surely we won't ever run low on memory?  The only possible place I can think of is if we want to specifically allocate memory on, say, a video card as opposed to system memory...

TIA

(Points at 500 now)
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> within dbgdel.cpp (using VS2008) called.
Right, but that's not calling your placement delete is it? It's calling normal delete.

>> What do you mean here?  Do some implementations differ?
The way new and delete are implemented is not prescribed by the C++ standard, you cannot make the assumption they use malloc/free.

>> I take it here that we never need a matching 'delete' to automatically clean up if an exception is thrown, because the memory is allocated on the stack?
If you heap allocated the memory used by placement new you must unallocate it manually, even if the objects constructor throws. In a normal new this is done automatically for you. In my example, the memory is stack based so nothing needs cleaning up.

>> but I don't see how this can be true, surely all we are doing is breaking the creation process up into two distinct steps (allocate memory then create object) as opposed to doing both at once?
For a single allocation probably not but it depends what you are allocating. For example, if you did lots of small heap allocations you'd fragment memory. You can define a custom allocation strategy to ensure this doesn't happen. Also, when allocating from heap the OS has to traverse the stack looking from a free block large enough to allocate. Again, you can optimise this using your own strategy. of course, a lot of this comes down to knowing, in advance, what you are allocating so you can use an allocation strategy specific to your needs.

>> Finally, can you state a place where this would be a crucial technique to use?
Anti-Virus engines, for example, will often pre-allocate memory to ensure they reserve enough for their own use before other processes start so even if the system runs out of memory the AV engine can still operator effectively and protect you.

Placement new is a very specialised thing... I can only recall one time when I had cause to use it... but it is very powerful. As Spider-man's uncle said, though, with great power comes great responsibility. :)
0
 
mrwad99Author Commented:
>> http://www.devx.com/tips/Tip/13612

That states

"As opposed to a common belief, placement delete does not invoke the destructor of its argument; in fact, it has no effect. To ensure that an object constructed by placement new is destructed, you need to call its destructor explicitly."

So I would be wrong to add a free, and later corrected by you to be delete[], to the override of operator delete in the first code I mentioned?  If I just call a destructor explicitly, how is that going to get rid of the heap allocated memory though?

>> If you heap allocated the memory used by placement new you must unallocate it manually

But the code I first posted shows that the placement delete operator is called automatically?!

>> In a normal new this is done automatically for you

Eh?  If I throw an exception which causes a matching 'delete' to be skipped, you're saying the memory gets deleted for free?

>> ...not but it depends what you are allocating.

Yeah, I can see that now.  I guess arrays and stuff could be subject to fragmentation, so it would be good for them.

>> Anti-Virus engines...

Good example, thanks.

Thanks again.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> So I would be wrong to add a free, and later corrected by you to be delete[], to the override of operator delete in the first code I mentioned?
Well, as we established, when you call delete on the object your placement delete operator isn't called.

take a look at http://www2.research.att.com/~bs/bs_faq2.html#placement-delete as I think this explains about placement delete far better.

>> If I just call a destructor explicitly, how is that going to get rid of the heap allocated memory though?
The destructors job isn't to free the memory it is just to destruct the object. It is the job (normally) of delete to free the memory in the case of placement new it is your job but you must still call the destructor to ensure the object is destructed properly.

>> But the code I first posted shows that the placement delete operator is called automatically?
But that's not what is happening is it? It isn't calling the placement delete and as the article says, "you can't call overloaded operator delete directly via the operator syntax; you'd have to code it as a regular function call".

>> Eh?  If I throw an exception which causes a matching 'delete' to be skipped, you're saying the memory gets deleted for free?
If you mean throwing in the objects constructor then yes, the memory is never allocated so you don't need to delete it.


try
{
   p = new Foo; // No need to delete if constructor throws
   delete p;
}
catch(...) {}

More info: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14

Also, note that the destructor is NOT called if the constructor fails in this way. This can be an issue, if the constructor allocated resource it won't get released as the destructor isn't called. For this reason you should always try to use RAII (or smart pointers) or ensure you use constructor try blocks to clean up in the face of an exception.

Like I said, I've used placement new once in my many years so it would be mis-leading if I was to claim to be an expert on this. That said, very few C++ programmers are as it's such a specialised topic. I'm sure, together, we can figure it out though :)
0
 
mrwad99Author Commented:
OK.  I think I am getting confused here.  Please bear with me, and appologies in advance for possibly (read: probably) being dumb.

>> Well, as we established, when you call delete on the object your placement delete operator isn't called.
>> But that's not what is happening is it?

The code I posted above, described in full at http://www.glenmccl.com/nd_cmp.htm, shows that this *is* the case.  Here is the code again.

       int flag = 0;

        typedef unsigned int size_t;

        void operator delete(void* p, int i)
        {
                flag = 1;
        }

        void* operator new(size_t s, int i)
        {
                return new char[s];
        }

        class A {
        public:
                A() {throw -37;}
        };

        int main()
        {
                try {
                        A* p = new (1234) A;
                }
                catch (int i) {
                }
                if (flag == 0)
                        return 1;
                else
                        return 0;
        }

The execution is as follows:

1) Construct a new A object on the heap via our placement new
2) The constructor throws an integer
3) The operator delete gets called, and sets 'flag' to 1.
4) The catch block gets called.

Now, if I don't have any sort of free, or delete[] calls in within operator delete, Visual Studio tells me there is a memory leak.  Hence this is why I decided I must actually do some freeing of the memory!

>> If you mean throwing in the objects constructor then yes, the memory is never allocated so you don't need to delete it.

OK, I didn't actually mean throwing in the constructor, but it stands to reason.  Of course, with what I have shown above, if using placement new, then (since the memory is already allocated) unless we have a matching delete, we would leak, correct?

OK.  With the code above, assuming I stop the constructor throwing, what is the correct way to delete my A object?

>> That said, very few C++ programmers are as it's such a specialised topic

Agreed.  I had never heard of it until I saw it on a list of random C++ questions...

0
 
evilrixSenior Software Engineer (Avast)Commented:
>> The code I posted above, described in full at http://www.glenmccl.com/nd_cmp.htm, shows that this *is* the case.  Here is the code again.
I think we're talking at cross-purposes :)

I am saying that you cannot call placement delete using the delete operator as this will just call normal delete (and things will go probably bang). You discovered this yourself when you tried it in http:#26104922 and found it went into the standard Microsoft delete code and not your operator placement delete (right?). This is consistent with what the article describes (but I probably didn't explain myself very well -- sorry).

>> Now, if I don't have any sort of free, or delete[] calls in within operator delete, Visual Studio tells me there is a memory leak.  Hence this is why I decided I must actually do some freeing of the memory!
Yup, and as the article says (and confirmed by Stroustrup in the other link I provided), you still need to explicitly delete this memory but "you'd have to code it as a regular function call".

NB. This is why I prefer the buffer to not be part of the class allocating but external and passed in as a pointer. It saves all this faffing around.

>>  Of course, with what I have shown above, if using placement new, then (since the memory is already allocated) unless we have a matching delete, we would leak, correct?
Correct, there is no magic that does it for you.
0
 
evilrixSenior Software Engineer (Avast)Commented:
NOTE: As state here http://www.devx.com/tips/Tip/13612

"As opposed to a common belief, placement delete does not invoke the destructor of its argument"

So it seems correct that the placement delete in the example does not delete the memory allocated, you have to do this explicitly yourself.
0
 
mrwad99Author Commented:
Ah ok.

>> I am saying that you cannot call placement delete using the delete operator as this will just call normal delete...

I thought when the author of that article said "I cannot call..." he meant "it won't compile", not that it just wouldn't work correctly!

Right then.  So if I say

A* p = new ( 1234 ) A;      // Assume constructor does not throw

in order to delete this I have to explicitly call my placement delete, like

p->~A();
operator delete ( p, 1234 );

correct?

>> NB. This is why I prefer the buffer to not be part of the class allocating...

What do you mean there?  Do you mean something like the example on "Is there a "placement delete"?" on the Stoustrup link, where the class Arena allocates memory via allocate?

>> So it seems correct that the placement delete in the example does not delete the memory allocated...

I agree it would be wrong for

void operator delete(void* p, int i)
{
      // Update our global
      flag = 1;
}

to call the destructor.  But are you saying that this should not even have a delete[] call in it?  That does not seem to make sense at all...
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> So it seems correct that the placement delete in the example does not delete the memory allocated, you have to do this explicitly yourself.
Additional observation I've made with the example code is that in the face of an exception, if placement delete doesn't free the memory I don't really see how else it can be free'd since once placement delete has been called the pointer to the memory allocated is lost! The pointer p is never allocated the address of the heap allocated!

>> in order to delete this I have to explicitly call my placement delete, like
You can't explicitly call it yourself (that I am aware of anyway).

>> Do you mean something like the example on "Is there a "placement delete"?" on the Stoustrup link, where the class Arena allocates memory via allocate
Yes, exactly or like I show in my first post

char buf[10];
A * pa = new(buf) A;

In this case you don't need to worry about coding a placement delete. Of course, buf could be heap allocated, you need to delete it if this is the case but you know you have a pointer to it so that's easy. In this case it makes perfect sense that placement delete does nothing (and I guess this is the reason for that being the default implementation, that and it has no idea how the buffer was allocated... it could be stack based).

If you go the allocator route (I quite like this I think, it emulates how STL allocators work) you just call deallocate as required.  http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14 shows this being called in there delete. I've provided a simplified version, below.

Thanks for this questions... I suspect I'm learning as much as you on this :)


struct Allocator
{
   void * alloc(size_t const n) { return new char[n]; };
   void dealloc(void* p) { delete [] p; }
};

void operator delete(void* p, Allocator & a)
{
   a.dealloc(p);
}

void* operator new(size_t s, Allocator & a)
{
   return a.alloc(s);
}

class A {
public:
   A() {throw -37;}
};

int main()
{
   Allocator a;

   A* p = 0;
   try {
      A* p = new (a) A;
      a.dealloc(p); // Deallocate memory (since we can't call placeemnt delete direct outselves
   }
   catch (int) {
      // a.dealloc() called automatically by placement delete
   }
}

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
>>  But are you saying that this should not even have a delete[] call in it?  That does not seem to make sense at all...
Given my observation in the post above, I'd tend to agree... this example doesn't seem right. It makes perfect sense default placement delete does nothing but in the case of a specialised placement delete I think I agree that it should be deleting the buffer. That said, I think this is a pretty poor example of using placement new and delete and I would not, personally, ever do this myself. I would either use an allocator (as show above) or a pre-allocated buffer (also shown above). The idea of getting the placement new to actually allocate the memory seems a bit pointless, you might as well just use normal new... right?
0
 
evilrixSenior Software Engineer (Avast)Commented:
NB. Obviously, in the allocator example above the allocator can allocate and deallocate memory however it wants... I only used new and delete in this example for brevity.
0
 
mrwad99Author Commented:
Excellent example, and thanks for sticking with me on this :)

>> You can't explicitly call it yourself (that I am aware of anyway).

I did do, it appeared to work too without complaint.  Besides, I thought that is what you were getting at when you were talking about normal delete using the global delete which of course is wrong...

A* p = new ( 1234 ) A;
p->~A();
operator delete ( p, 1234 );

works fine.

Regarding it being a poor example, well, yeah: I kind of agree with you.  I just wanted to make sure that I fully understood it.

The only issue I have with the example code is that we free the memory, but never call the destructor of the A object...I guess it would need to be changed a-la the Stroustrup example?
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> I did do, it appeared to work too without complaint.
Ah, interesting. I did try it myself but it didn't work. I think I must have had a typo when I first tried it cos I tried it again and you are absolutely right. You have taught me something today :)

>> The only issue I have with the example code is that we free the memory, but never call the destructor of the A object...I guess it would need to be changed a-la the Stroustrup example?
Yeah, that's my bad. There should have been a p->~A() in there somewhere (darn, see how easy it is to mess up using placement new!). Note, though, you only call the destructor if the constructor worked. If it fails you don't destruct because the object was never fully constructed.

For consistency, below is the "fixed" code.

>> thanks for sticking with me on this :)
Thank you. Like I said I think I've probably learned as much in this thread as you! I feel like I should be awarding you the points ;)

struct Allocator
{
   void * alloc(size_t const n) { return new char[n]; };
   void dealloc(void* p) { delete [] p; }
};

void operator delete(void* p, Allocator & a)
{
   a.dealloc(p);
}

void operator delete(void* p, int)
{
}

void* operator new(size_t s, Allocator & a)
{
   return a.alloc(s);
}

class A {
public:
   A() {throw -37;}
};

int main()
{
   Allocator a;

   A* p = 0;
   try {
      A* p = new (a) A;

      p->~A(); // Don't forget to call the destructor (like I did above)!

      a.dealloc(p); // Deallocate memory (since we can't call placeemnt delete direct outselves
   }
   catch (int) {
      // a.dealloc() called automatically by placement delete (you should NOT call the destructor here).
   }

   operator delete(p, 0);
}

Open in new window

0
 
mrwad99Author Commented:
Excellent.  Once again many thanks.  All the best for the festive period :)
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> All the best for the festive period :)
You too my friend :)
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

  • 12
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now