Reputation: 3164
Hello I am on chapter 19 from C++ primer 5th edition. 'Operator new
and delete
vs new
and delete
expression and placement new
':
AFAIK operator new
and operator delet
e allocate and deallocate memory respectively but don't construct an object there. On the other hand a new-expression
calls operator new
to allocate memory, construct an object in that memory address and finally returns a pointer to the newly allocated and initialized object.
So for the understanding sake I've tried this:
struct Foo{
Foo(){std::cout << "Foo()\n";}
~Foo(){std::cout << "~Foo()\n";}
void bar() const{
std::cout << "Foo::bar()\n";
}
};
int main(){
Foo* pf = (Foo*)operator new(sizeof(Foo)); // Foo() is not called! Is it UB?
pf->bar(); // looks to work fine. Does it really?
delete pf; // looks fine?
Foo* pf2 = new Foo{}; // ok Foo() is called
pf2->bar(); // OK
delete pf2; // OK ~Foo() is called
}
As you can see in the first example I've called operator new directly, and I guess this latter does allocate memory only but doesn't construct an object there and finally it returns a pointer to void pointing to the newly allocated member.
So I don't get the constructor called Foo()
. Now why calling a member function works fine? pf->bar()
? or does this yield an undefined behavior?
The second example (pf2
) is straightforward.
Upvotes: 2
Views: 215
Reputation: 29022
This is Undefined Behavior. pf
is a Foo*
that does not point to an instance of Foo
so you cannot dereference it. It looks like it works for the same reason using a pointer after you delete
it might look like it works. In this case, since bar()
doesn't access this
, it is similar to a static
member function and the observed behavior will likely be that it will print the message. But you can't rely on this, the behavior may change for no obvious reason. You shouldn't expect C++ to complain or otherwise diagnose when you have Undefined Behavior.
delete pf; // looks fine?
delete pf;
is not fine because pf
was not created by a new expression (calling operator new
does not constitute a new expression). You need to use operator delete
to free the memory. This is again Undefined Behavior.
Case #1 is not safe and not correct. You cannot use an uninitialized object. You can initialize it using placement new :
void * memptr = operator new(sizeof(Foo));
Foo* pf = new (memptr) Foo;
You still can't use delete
here to destroy the object created by a placement new expression. You need to call the destructor explicitly, then use operator delete
to separately free the memory.
pf->~Foo();
operator delete(memptr);
Upvotes: 1
Reputation: 40013
Unless you use placement new (which is basically the other half of the ordinary new
), no Foo
object exists, so you can't call a member function on it. Moreover, if you do use placement new, you must call the destructor yourself:
Foo* pf = new (operator new(sizeof(Foo))) Foo; // no cast needed
pf->bar();
pf->~Foo();
operator delete(pf); // analogous, though not equivalent, to std::free
Upvotes: 2