which new operator will be called new or new[]? - c++

In the below program overloaded operator new [] is getting called. But if I comment this function then my overloaded operator new is getting called. Shouldn't It called default new [] operator?
#include <iostream>
#include <stdlib.h>
using namespace std;
void *operator new (size_t os)
{
cout<<"size : "<<os<<endl;
void *t;
t=malloc(os);
if (t==NULL)
{}
return (t);
}
//! Comment This below function
void* operator new[](size_t size){
void* p;
cout << "In overloaded new[]" << endl;
p = malloc(size);
cout << "size :" << size << endl;
if(!p){
}
return p;
}
void operator delete(void *ss) {free(ss);}
int main ()
{
int *t=new int[10];
delete t;
}

Looking at the reference, we see:
void* operator new ( std::size_t count );
Called by non-array new-expressions to allocate storage required for a single object. […]
void* operator new[]( std::size_t count );
Called by the array form of new[]-expressions to allocate all storage required for an array (including possible new-expression overhead). The standard library implementation calls version (1)
Thus, if you overload version (1) but do not overload version (2), your line
int *t = new int[10];
will call the standard library's operator new []. But that, in turn calls operator new(size_t), which you have overloaded.

There is one difference between them. With "new" keyword, it just allocates raw memory. The result is a real live object created in that memory. If you don't call your function, new is getting called regular.

operator new is called by operator new[]
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/new_opv.cc#L32

Related

Getting issue with placement new and delete operator

I have written the following code for placement new and delete operator functions. Can you please tell the issue with the code below.
// new_operator.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
using namespace std;
class Mem
{
public:
void* alloc(size_t sz) { return malloc(sz); }
void dealloc(void* ptr) { free(ptr); }
};
class Object
{
public:
Object() { cout << "In Constructor Object()" << this << endl; }
~Object() { cout << "In Destuctor ~Object()" << endl; }
void* operator new(size_t sz, Mem* handle)
{
Object* x1 = (Object*)handle->alloc(sz);
return x1;
}
void operator delete(void* ptr, Mem* handle)
{
cout << "Here\n";
((Object*)(ptr))->~Object();
handle->dealloc(ptr);
}
};
int main()
{
Mem* memory = new Mem;
Object* obj = new (memory) Object;
cout << "Obj is " << obj << endl;
delete (obj, memory);
delete memory;
return 0;
}
I'm getting runtime crashes at the time when delete operator function starts executing. Can anyone please tell what I'm doing wrong.
Placement delete is called to free memory when a constructor called from placement new fails. You are not supposed to call any destructors from any version of operator delete, because operator delete frees memory that is left after an object that used to reside there is destroyed (or was never constructed to begin with).
The only way to explicitly call a placement operator delete is to spell out two words operator delete, thus making a function-call-expression. You cannot invoke it from a delete-expression (there is no placement-delete-expression syntax). In your case, you would need to use a qualified name: Object::operator delete. Note that if you remove the explicit destructor call from Object::operator delete, as you should because of the above, the destructor will not be called. There is no way to both invoke the destructor and free the memory in a single call to a placement delete. The easiest way to handle this is to create and use a non-static member function, say void Object::destroy(Mem*).
delete (obj, memory);
On this line, you delete only memory, not obj. The left hand operand of comma operator is discarded. Since the expression obj has no side-effects, this is probably a mistake.
delete memory;
On this line, you delete memory again. This results in undefined behaviour.
Note that you never destroy the dynamic Object that you created. The custom placement delete overload will only be called in case the placement new throws an exception. In other cases, your malloc will leak.

size_t parameter new operator

I have a point in my mind which I can't figure out about new operator overloading.
Suppose that, I have a class MyClass yet MyClass.h MyClass.cpp and main.cpp files are like;
//MyClass.h
class MyClass {
public:
//Some member functions
void* operator new (size_t size);
void operator delete (void* ptr);
//...
};
//MyClass.cpp
void* MyClass::operator new(size_t size) {
return malloc(size);
}
void MyClass::operator delete(void* ptr) {
free(ptr);
}
//main.cpp
//Include files
//...
int main() {
MyClass* cPtr = new MyClass();
delete cPtr
}
respectively. This program is running just fine. However, the thing I can't manage to understand is, how come new operator can be called without any parameter while in its definition it has a function parameter like "size_t size". Is there a point that I am missing here?
Thanks.
Don't confuse the "new expression" with the "operator new" allocation function. The former causes the latter. When you say T * p = new T;, then this calls the allocation function first to obtain memory and then constructs the object in that memory. The process is loosely equivalent to the following:
void * addr = T::operator new(sizeof(T)); // rough equivalent of what
T * p = ::new (addr) T; // "T * p = new T;" means.
(Plus an exception handler in the event that the constructor throws; the memory will be deallocated in that case.)
The new-expression new MyClass() is basically defined in two steps. First it calls the allocator function, which you have overloaded, to get some allocated memory. It passes the size of the type MyClass to that allocator function, which is why the size_t argument is required. After this, it constructs an object in that allocated memory and returns a pointer to it.
The compiler knows the size of your class. Basically, it's passing sizeof(MyClass) into your new function.

Why operator new function - placement form ok in class level?

We know from c++ 11(also true in c++98/03 standard) standard(see below), we cannot try to replace the operator new function - placement form in global space as it has already been defined.
18.6.1.3 Placement forms [new.delete.placement]
These functions are reserved, a C++ program may not define functions that displace the
versions in the Standard C++ library (17.6.4). The provisions of
(3.7.4) do not apply to these reserved placement forms of operator new
and operator delete.
This has been proven by point 2> in the snippet below, compile error as expected.
But I can still override the placement new in class level,that works fine, see point (2) in snippet below. Why is that? Shouldn't compile should try to prevent (2) as well according to standard ???
See my snippet below:
class Test
{
public:
Test(int i):m_i(i) { cout << "Test::Test()" << endl; }
~Test() { cout << "Test::~Test()" << endl; }
//(1)class level override placement new
void* operator new (std::size_t size) throw (std::bad_alloc) {
cout << "My class level new" << endl;
return malloc(size);
}
//(2)class level override placement new
void* operator new (std::size_t size, void* ptr) throw() {
cout << "My class level non-throwing placement new" << endl;
return ptr;
}
private:
int m_i;
};
//<1>global replacement for operator new - single object form
void* operator new (std::size_t size) throw (std::bad_alloc) {
cout << "My global new" << endl;
return malloc(size);
}
//<2>global replacement for operator new - replcement form
//NB. This is a attempt that definitely fails according to c++ stadnard:
//does get compile error: error: redefinition of 'void* operator new(std::size_t, void*)'
/*
void* operator new (std::size_t size, void* ptr) throw() {
cout << "My global non-throwing placement new" << endl;
return ptr;
}
*/
int main() {
Test* p = new Test(1);
delete p;
cout << "" << endl;
void* mem = operator new(sizeof(Test));
Test* p2 = new(mem) Test(1);
p2->~Test();
operator delete (mem);
return 0;
}
Below is output as expected:
My class level new
My global new
Test::Test()
Test::~Test()
My global new
My class level non-throwing placement new
Test::Test()
Test::~Test()
==================================================================================
Further clarification for my question:
18.6.1.3 Placement forms These functions are reserved, a C++ program may not define functions that displace the versions in the
Standard C++ library (17.6.4). The provisions of (3.7.4) do not apply to these reserved placement forms
of operator new and operator delete.
This explains the expected compile error at point <2> in my snippet, so this one is ok.
But why I can displace the placement forms in the class level at point (2) inside the class clarification?
§18.6.1.3 lists the following forms:
void* operator new(std::size_t size, void* ptr) noexcept;
void* operator new[](std::size_t size, void* ptr) noexcept;
void operator delete(void* ptr, void*) noexcept;
void operator delete[](void* ptr, void*) noexcept;
The rule that "a C++ program may not define functions that displace the versions in the Standard C++ library" applies only to these four function declarations, which are not in any namespace. If you make your own version in a class or a namespace, that's fine.
In fact, sometimes you have to provide your own placement new. If you declare a normal operator new in your class, it will hide the placement new provided by the standard library, and you'll need to add your own placement new in the class if you ever want to use the new (ptr) T(...) syntax.
This simply provides a guarantee that the call ::new (ptr) T(...) is guaranteed to behave like the standard placement new. (Note the :: prefix.)

Does casting a pointer to "void*" have any effect when placement new is called?

I'm reviewing code of a custom container and some portions of it create elements like this:
::new( (void*)&buffer[index] ) CStoredType( other );
and some do like this:
::new( &buffer[index] ) CStoredType( other );
So both use placement new to invoke a copy constructor to create an element by copying some other element, but in one case a pointer to the new element storage is passed as is and in another it is casted to void*.
Does this cast to void* have any effect?
Yes you could overload operator new for a nonvoid pointer. The cast ensures that the void pointer overload is taken.
For example
void* operator new(size_t s, env * e);
A compilable example:
#include <iostream>
#include <new>
void* operator new(std::size_t, int* x)
{
std::cout << "a side effect!" << std::endl;
return x;
}
int main()
{
int buffer[1];
new ((void*)&buffer[0]) char;
new (&buffer[0]) char;
}

Questions about operator new() and operator delete()

Consider the following code and the questions below:
/*
* GCC 4.4
*/
#include <iostream>
using namespace std;
class A {
public:
void* operator new(size_t s) {
cout << "A::operator new(size_t) called\n";
}
void operator delete(void* p) {
cout << "A::operator delete(void*) called\n";
}
void* operator new(size_t s, A* p) {
cout << "A::operator new(size_t, A*) called\n";
}
void operator delete(void* p, size_t s) {
cout << "A::operator delete(void*, size_t) called\n";
}
};
void* operator new(size_t s) {
cout << "::operator new(size_t) called\n";
}
void operator delete(void* p) {
cout << "::operator delete(void*) called\n";
}
void* operator new(size_t s, A* p) {
cout << "::operator new(size_t, A*) called\n";
}
void operator delete(void* p, size_t s) {
cout << "::operator delete(void*, size_t) called\n";
}
int main() {
A* p1 = new A(); // See question 1.
delete p1; // See question 2.
A* p2 = new (p1) A(); // See question 3.
delete p2; // See question 4.
}
The questions below might seem redundant somehow. However, what I am trying to distinguish is what is defined by the C++ standard rules from what is defined by the implementation.
operator new(size_t) will be used in any case (taken from A or from the global
namespace, be it default or not). This is OK.
Now try to remove void* A::operator new(size_t) {} only: why does the compiler gives:
error: no matching function for call to ‘A::operator new(unsigned
int)’
note: candidates are: static void* A::operator new(size_t, A*)
Connot the compiler pick up ::operator new(size_t) from the global
namespace?
Why is operator delete(void*) preferred to operator delete(void*, size_t)
(when both of those versions are present in the same namespace where operator delete (void*) is taken from)?
Why will not the code compile if I remove void* A::operator new(size_t, A*),
although there is the same version of the operator defined in the global namespace?
error: no matching function for call to ‘A::operator new(unsigned int,
A*&)’
note: candidates are: static void* A::operator new(size_t)
Why does the compiler still prefer
operator delete (void*), although A::operator new(size_t, A*) has been used
for getting p2?
Let's imagine some scenarios. First off, the following always works:
A * p1 = ::new A;
::delete p1;
A * p2 = ::new (addr) A; // assume "void * addr" is valid
p2->~A();
The global expressions always use the corresponding operators from the global namespace, so we're fine. Note that there is no "placement-delete" expression. Every placement-constructed object must be destroyed explicitly by calling the destructor.
Next up, suppose we write:
A * p3 = new A;
delete p3;
This time round, the allocation function operator new(size_t) is looked up in the A's scope first. The name exists, but if you remove the correct overload, you have an error. (This answers Q1 and Q3.) The same goes for operator delete(). There's no particular reason why the one-parameter version ((void *)) is preferred over the two-argument version ((void *, size_t)); you should just have one of the two. (Note also that there's no global version of the two-argument function.)
Finally, let us revisit placement-new expressions. Since there is no placement-delete expression, your final line of code is an error (undefined behaviour): You mustn't delete anything that wasn't obtained through a default-new expression. If you define a placement-new allocation function, you should also define the matching deallocation function. This function will only be called automatically on one specific situation, though: If a placement-new expression new (a, b, c) Foo; causes the constructor to throw an exception, then the corresponding deallocation function is called. Otherwise, since all placement-construction is manual, you will typically only call the placement deallocation function manually (and often never at all, because it rarely does any actual work).
The typical scenario might be something like this:
void * addr = ::operator new(sizeof(Foo)); // do real work
Foo * p = new (addr, true, 'a') Foo; // calls Foo::operator new(void*, bool, char);,
// then calls the constructor Foo::Foo()
// in case of exception, call Foo::operator delete(addr, true, 'a')
p->~Foo();
Foo::operator delete(addr, true, 'a'); // rarely seen in practice, often no purpose
::operator delete(addr); // do real work
To come full circle to the opening code example, note that the standard demands that the global ::operator delete(void *, void *) do nothing. That is, global placement-new is required to need zero clean-up.
As to your first and third question, it IMO works like that:
Because you didn't use ::new, the compiler tries to find a new operator in the A class.
It finds one, but it cannot find the proper overload, so it fails.
If you explicitly state ::new, it shouldn't have any problem. The compiler only goes to the global namespace if it cannot find the specialized version of the new operator in the class.
From the standard: § 5.3.4,
9. If the new-expression begins with a unary :: operator, the allocation function’s name is looked up in the
global scope. Otherwise, if the allocated type is a class type T or array thereof, the allocation function’s
name is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a
class type, the allocation function’s name is looked up in the global scope.
An object does not remember how it was created; placement delete is only used when the corresponding placement new throws, otherwise the regular delete operator is used.