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.
Related
Calling local overload of operator new causes stack overflow due to infinite recursive calls but when same happens with local overload of operator delete, why global operator delete is called (hence avoiding the stack crash).
Simple code goes like this-
class A {
public:
void * operator new(size_t n) {
//return new A();calls local overloaded version and stack overflows
return ::new A();
}
void operator delete(void* p)
{
delete(p);//why its calling global version?
//::delete(p);//calls global version
}
};
int main()
{
A *a = new A();
delete(a);
}
My question is why delete from overloaded operator delete doesn't call itself but the global operator delete?
I'm trying to summarize my comments into the answer.
delete is a keyword, not a function or operator. So it does not behave like functions.
When you write delete p, compilers does not perform lookup for overloads like for functions. When a compiler meets the expressions delete p it performs lookup between available overloads operator delete for the type of the pointer p. If p is a pointer to a class, and a class specific overload exists then p->operator delete(some_ptr) is called. Otherwise a compiler performs lookup between scoped void operator delete(void*).
Returning to you example.
A *a = new A();
delete(a); // a is pointer to class, calls a->operator delete(a);
void A::operator delete(void* p) {
delete(p); // p is pointer to void, calls ::operator delete(p);
}
If you call operator delete(a);, it is like a function call, and A::operator delete(void*); is not called.
If you call operator delete(p); from the inside of A::operator delete(void* p);, you get the infinite recursion.
If you call delete static_cast<A*>(p); from the inside of A::operator delete(void* p);, you get the infinite recursion again.
I have an object of type MyType that, for SSE reasons, needs to be 16-byte aligned. So, I wrote an allocator and overloaded the new operators. Methods in MyType:
inline static void* operator new(size_t size) {
awesome::my_allocator<MyType,16> alloc;
return alloc.allocate(size);
}
inline static void* operator new[](size_t size) { return operator new(size); }
inline static void operator delete(void* ptr) {
awesome::my_allocator<MyType,16> alloc;
alloc.deallocate(reinterpret_cast<MyType*>(ptr),0); //last arg ignored in my impl
}
inline static void operator delete[](void* ptr) { operator delete(ptr); }
Now, for cache-locality reasons, I need to copy-construct an instance into a particular piece of 64-byte-aligned memory:
void MyType::copy_into(uint8_t* ptr) const {
new (reinterpret_cast<MyType*>(ptr)) MyType(*this);
}
GCC tells me:
error: no matching function for call to ‘MyType::operator new(sizetype, MyType*)’
ICC tells me:
error : function "MyType::operator new" cannot be called with the given argument list
1> argument types are: (unsigned __int64, MyType *)
As I understand it, the placement new operator is provided by the C++ implementation (or possibly by <new>, which I also tried #includeing?) and simply returns its argument (new makes memory available, and placement new is the programmer saying that the given memory is available).
Curiously, the error does not occur when the (ordinary!) new operators defined above are not in the class. Indeed, MyOtherType, which doesn't define them, works just fine.
Question: what's going on? How should I fix it?
Since you have defined operator new in your class, you need to use the global new to use the placement version of it.
#include <new>
...
::new (reinterpret_cast<MyType*>(ptr)) MyType(*this);
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.)
This document contains the following text and code :
If you use the placement new form of the new operator, the form with arguments in addition to the size of the allocation, the compiler does not support a placement form of the delete operator if the constructor throws an exception. For example:
// expre_new_Operator2.cpp
// C2660 expected
class A {
public:
A(int) { throw "Fail!"; }
};
void F(void) {
try {
// heap memory pointed to by pa1 will be deallocated
// by calling ::operator delete(void*).
A* pa1 = new A(10);
} catch (...) {
}
try {
// This will call ::operator new(size_t, char*, int).
// When A::A(int) does a throw, we should call
// ::operator delete(void*, char*, int) to deallocate
// the memory pointed to by pa2. Since
// ::operator delete(void*, char*, int) has not been implemented,
// memory will be leaked when the deallocation cannot occur.
A* pa2 = new(__FILE__, __LINE__) A(20);
} catch (...) {
}
}
int main() {
A a;
}
As expressed in the second comment line above, the code emits
C2660:'operator new':no overloaded function takes 3 arguments
The upshot is that you always have to implement custom versions of operator new() and operator delete() in matching pairs. This may at first seem unnecessary, since there is no "placement-delete expression": The only way to destroy a placement-new-constructed object is by manual invocation of the destructor:
A * p = new (addr, true, BLUE) A(1, 'a', x);
// uses void * A::operator new(std::size_t, void *, bool, EnumColour) to
// allocate, then invokes constructor A::A(int, char, X) with "this = p".
// ... it's almost over ...
p->~A(); // now it's over!
When you look at this, you notice that there is no hypothetical "delete (addr, true, BLUE) p". So why would you need to implement void A::operator delete(void *, bool, EnumColour)? The answer is precisely the situation described by the text you quoted: When the constructor of the object throws an exception, then the compiler automatically tries to invoke the matching delete function:
struct A {
A(int, char, X) { throw std::runtime_error("Boo!"); }
// ...
static void operator delete(void *, bool, EnumColour) noexcept;
};
If that function doesn't exist, no function is called at all. Therefore, if you somehow have to take care of cleaning up resources (e.g. move a pool pointer around or update a free list), this will not occur.
I'm dang certain that this code ought to be illegal, as it clearly won't work, but it seems to be allowed by the C++0x FCD.
class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X(); // according to the standard, the RHS is a placement-new expression
::operator delete(p); // definitely wrong, per litb's answer
delete p; // legal? I hope not
Maybe one of you language lawyers can explain how the standard forbids this.
There's also an array form:
class X { /* ... */};
void* raw = malloc(sizeof (X));
X* p = new (raw) X[1]; // according to the standard, the RHS is a placement-new expression
::operator delete[](p); // definitely wrong, per litb's answer
delete [] p; // legal? I hope not
This is the closest question I was able to find.
EDIT: I'm just not buying the argument that the standard's language restricting arguments to function void ::operator delete(void*) apply in any meaningful way to the operand of delete in a delete-expression. At best, the connection between the two is extremely tenuous, and a number of expressions are allowed as operands to delete which are not valid to pass to void ::operator delete(void*). For example:
struct A
{
virtual ~A() {}
};
struct B1 : virtual A {};
struct B2 : virtual A {};
struct B3 : virtual A {};
struct D : virtual B1, virtual B2, virtual B3 {};
struct E : virtual B3, virtual D {};
int main( void )
{
B3* p = new E();
void* raw = malloc(sizeof (D));
B3* p2 = new (raw) D();
::operator delete(p); // definitely UB
delete p; // definitely legal
::operator delete(p2); // definitely UB
delete p2; // ???
return 0;
}
I hope this shows that whether a pointer may be passed to void operator delete(void*) has no bearing on whether that same pointer may be used as the operand of delete.
The Standard rules at [basic.stc.dynamic.deallocation]p3
Otherwise, the value supplied to operator delete(void*) in the standard library shall be one of the values returned by a previous invocation of either operator new(size_t) or operator new(size_t, const std::nothrow_t&) in the standard library, and the value supplied to operator delete[](void*) in the standard library shall be one of the values returned by a previous invocation of either operator new[](size_t) or operator new[](size_t, const std::nothrow_t&) in the standard library.
Your delete call will call the libraries' operator delete(void*), unless you have overwritten it. Since you haven't said anything about that, I will assume you haven't.
The "shall" above really should be something like "behavior is undefined if not" so it's not mistaken as being a diagnosable rule, which it isn't by [lib.res.on.arguments]p1. This was corrected by n3225 so it can't be mistaken anymore.
The compiler doesn't really care that p comes from a placement new call, so it won't prevent you from issuing delete on the object. In that way, your example can be considered "legal".
That won't work though, since "placement delete" operators cannot be called explicitly. They're only called implicitly if the constructor throws, so the destructor can run.
I suppose you might get away with it (on a particular compiler) if
new/delete are implemented in terms of malloc/free and
the placement new actually uses the same mechanism for keeping track of the destructor associated with allocations as the standard new, so that the call to delete could find the right destructor.
But there is no way it can be portable or safe.
I found this in the library section of the standard, which is about as counter-intuitive a location (IMO) as possible:
C++0x FCD (and n3225 draft) section 18.6.1.3, [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.3). The provisions
of (3.7.4) do not apply to these
reserved placement forms of operator
new and operator delete.
void* operator new(std::size_t size, void* ptr) throw();
void* operator new[](std::size_t size, void* ptr) throw();
void operator delete(void* ptr, void*) throw();
void operator delete[](void* ptr, void*) throw();
Still, the section defining legal expressions to pass to delete is 5.3.5, not 3.7.4.