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

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.)

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.

which new operator will be called new or new[]?

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

Overloading new for a class

I can declare in the header file for MyClass something like:
void* operator new(size_t size) throw(bad_alloc);
and in the MyClass source file define:
void* MyClass::operator new(size_t size) throw(bad_alloc)
{
cout << "overloading new" << endl;
return (::operator new(size));
}
and to use this:
MyClass *m = new MyClass();
So my question is- in the above line of code where we use the overloaded new operator- I cannot see us passing the size argument of type size_t to the overloaded new operator?? Yet in the definition for the overloaded new operator it requires it?
Short answer
The size is infered from the compiler depending on the size of the object which is created with the new operator.
Example
struct Example {
int X;
int Y;
}
Example *A = new Example();
would call the new operator/function with the parameter size equal to 8 (16 on x64 systems), it can also be more or less depending on alignment.
The new call would be translated from the compiler as follows (if no exceptions were used in the constructor and if the compiler decides to optimize away the catching of the not needed catch block):
Example *A = (Example*)Example::new(sizeof(Example));
A->A(); // call constructor

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.

Can I prevent invoking destructor before overloaded delete?

I'd like to use boost.pool. It's okay if you don't know about it. Basically, it has two main functions, malloc() and free().
I've overloaded new and delete for my custom defined class test.
class test
{
public:
test()
{
cout << "ctor" << endl;
}
~test()
{
cout << "dtor" << endl;
}
void* operator new(size_t) throw()
{
cout << "custom operator new" << endl;
return _pool.malloc();
}
void operator delete(void* p)
{
cout << "custom operator delete" << endl;
_pool.free(p);
}
void show()
{
cout << _i << endl;
}
private:
int _i;
static boost::pool<> _pool;
};// class test
boost::pool<> test::_pool(sizeof(test));
When I create instance of test using new, constructor was not called but if I delete it, destructor was called. Why? and can I avoid it?
Can't reproduce, when added
#include <iostream>
#include <boost/pool/pool.hpp>
using namespace std;
(why do people omit such things that are necessary to make the code compile?!) and
int main()
{
test* p = new test;
delete p;
}
This is either a stripped-down and modified version that doesn't have that behavior or your compiler may be broken (which version is it?)
In any case your aim should be getting the constructor called, rather than getting destructor not called. Overloaded operator new just deals with raw memory allocation, the built-in new-expression should use that to obtain the memory and then call the constructor to create an instance there.
Edit: the only way I can reproduce your output is by circumventing the built-in new-expression:
test* p = static_cast<test*>(test::operator new(sizeof (test)));
Could it be because the global operator new is getting called? Anyways, just a comment about your class...
operator new and operator delete are always static (even if you don't write the keyword), so it's good practice to use static in the declaration.
You declared operator new with throw(), meaning that it won't throw. But you use a statement (iostreaming) that can throws. Maybe you should surround that with try/catch and create an std::nothrow_t version.