Is whether the placement new operator is solely responsible to the construct object

105 Views Asked by At

Let me share my Understanding on new operator. new operator do two jobs.

  1. Allocate memory
  2. construct memory at same place.

The new operator allocates memory using the global method::operator new(), and the memory is constructed at the same location using the placement new operator. The placement new is also in a global version.

If I overload the new operator in my class, the compiler will disable the use of global methods for memory allocation and construction for the same class. This means that I need to overload the new operator to allocate memory and the placement new operator to construct memory. In the following example, I am just overloading the new operator to allocate memory.

#include <iostream>
using namespace std;

class Base
{
    public:
    Base()
    {
        cout << __FUNCTION__ << endl;
    }
    
    void* operator new(size_t _size)
    {
        cout << "Base new operator" << endl;
        void *p = ::operator new(_size); // allocating dynamic memory using global new defination
        
        if(p == NULL)
        {
            cout << "Sorry, Memory allocation failed";
            return NULL;
        }
        return p;
    }
};

int main()
{
    Base *p = new Base();

    return 0;
}

Output:

Base new operator
Base

Memory allocation is done with the overloaded new operator, and I'm not sure if memory is constructed using the global placement new operator; if so, who is calling the placement new operator, and if not, how is the same memory is constructed without the placement new operator?

To find out what happens if I overload the placement new operator. I tried the following example.

#include <iostream>
using namespace std;

class Base
{
    public:
    Base()
    {
        cout << __FUNCTION__ << endl;
    }
    
    void* operator new(size_t _size)
    {
        cout << "Base new operator" << endl;
        void *p = ::operator new(_size); // allocating dynamic memory using global new defination
        
        if(p == NULL)
        {
            cout << "Sorry, Memory allocation failed";
            return NULL;
        }
        return p;
    }
    
    void* operator new(size_t __size, void*p)
    {
        cout << "Base Placement new" << endl;
        return p;
    }
};

int main()
{
    Base *p = new Base();

    return 0;
}

output:

Base new operator
Base

Still placement operator is not called to construct the allocated same memory.

This may be a stupide question, but if someone can assist me in resolving my doubt, then your helpful advice will greatly improve my understanding.

3

There are 3 best solutions below

1
Andreas Loanjoe On

The object is emplaced in the memory returned by your overloaded operator new. There is no way to override the emplacement itself, you can only override how it allocates the memory. If you want to have control over the placement aswell you will need to do something else than overriding the new operator (allocate memory and construct_at in another function for example).

2
Guillaume Gris On

At a high level new is used to construct an object.

When using the allocating variant, it first allocates the memory then calls the constructor on the allocated memory.

When using the placement new variant, it only calls the constructor on the provided memory (assuming the pointer you give points at a suitable chunk of memory)

If you override the allocating new operator. When overloading it, you don’t override the constructing part, you only override the memory allocation part (hence the type agnostic signature). ::operator new(size) is basically equivalent to malloc.

If you override the placement new operator: void* operator new(size_t size, void* ptr), and call it, it will call your placement new version then call the constructor.

So your overload is only allocating memory and the constructor will be called on the memory returned by your overloaded new. Even if you overload the placement new operator, if you call the allocating new it won’t call the placement one.

0
user17732522 On

The problem is that there are two related constructs in C++ that are called new.

The first one is the new-expression, e.g. new Base() in your code, and the second one is a group of functions with the name operator new or operator new[], collectively called allocation functions.

The former, as part of its semantics may or may not call an allocation function and the user may to some degree replace or declare new allocation functions.

But a new expression is not equivalent to the allocation functions and it is not an operator overload. A new-expression will, as long as an allocation function call doesn't fail, always create, start the lifetime of and initialize an object of the specified type into the memory obtained by the allocator call (or obtained in another way).

That part of the new expressions semantics is distinct from the allocation function and can't be affected by the user. There is also no way to explicitly create or start the lifetime of an object in the core language other than by using that part of a new-expression's semantics.

There is one special form of a placement-new that will only do this part into some memory that has already been obtained in another way, i.e. the placement-new expression of the form

::new(ptr) T/*inializer*/

where T is the type of the object and ptr is a void* to the memory location.

The whole set of rules how new-expressions relate to allocation functions is rather complicated. Also, the whole object model in C++ is complicated and doesn't match the intuitive understanding that most developers seem to have. So I would suggest avoiding using these constructs without reading up on the details first.

For full rules, see [expr.new] in the standard for specification of new-expressions, [basic.stc.dynamic.allocation] for specification of allocation functions in general and [new.delete] for specification of the library-provided allocation functions and their user-replacements.