Itachi Uchiwa
Itachi Uchiwa

Reputation: 3164

If I call operator new directly without a new expression and cast the return pointer type safe?

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 delete allocate and deallocate memory respectively but don't construct an object there. On the other hand a new-expressioncalls 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

Answers (2)

Fran&#231;ois Andrieux
Fran&#231;ois Andrieux

Reputation: 29022

  • Now why calling a member function works fine? pf->bar()? or does this yield an undefined behavior?

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.

  • If one is safe and correct, what happened? how could I use an uninitialized object?

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

Davis Herring
Davis Herring

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

Related Questions