Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undefined behavior or memory leak when using placement-new

I am learning about placement-new in C++ using the books listed here. Now, to look at some examples, I came across the following snippet in one of the SO post that claims that it (the given example) has undefined behavior :

For example, this has UB:

void ub() {
   alignas(string) char buf[sizeof(string)]; // memory is allocated
   new(buf) string("1");                     // string("1") is constructed
} // memory is deallocated but string("1") outlives the memory! 

As you can see the user claims that the above snippet has undefined behaviour. But I think that it has memory leak and not UB. Can someone tell me whether the above snippet has UB or memory leak or both and if my understanding (that it has memory leak but not UB) is correct or not.


2 Answers

There is a sentence in the standard which is not very clear about its meaning in [basic.life]/5 saying that if a destructor call is omitted like in your quoted example, then

any program that depends on the side effects produced by the destructor has undefined behavior.

It is not clear what "depends on the side effects" here is supposed to mean. If you consider the side effect of leaking memory something that your program "depends" on, then maybe it applies, but I doubt that this is the intended reading.

There is CWG issue 2523 suggesting to remove this phrase and replace with just a non-normative note mentioning the potential problems of not calling the destructor in such a situation. See also discussion here.

Aside from that, there is no undefined behavior, just a memory leak. Of course with other types than string it could easily be possible to cause undefined behavior if you don't properly call destructors before deallocating their memory.

In practice you should never let this situation happen, even if only to avoid the memory leak. So you can practically treat it almost like undefined behavior.

like image 199
user17732522 Avatar answered Jan 28 '26 13:01

user17732522


Nothing really wrong with your code in this case other than the obvious leaking of memory.

The constructor for the type you construct could have side effects though, like adding the constructed object to a global list of all such objects. The destructor would then remove the object from said list but you never call the destructor. So the global list ends up with a dangling pointer.

Note: Modern C++ has construct_at to replace your placement new.

like image 45
Goswin von Brederlow Avatar answered Jan 28 '26 15:01

Goswin von Brederlow



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!