Could someone explain what this MS text is trying to convey? - c++

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.

Related

Override 'new' with a pool allocator; return NULL?

Is there a way to not call a class constructor if operator new returns null?
Consider this class C:
class C {
public:
C() { printf("%p->C()\n", this); }
~C() { printf("%p->~C()\n", this); }
static void* operator new(std::size_t sz) {
printf("new!\n");
return NULL;
}
};
int main()
{
C* c = new C();
printf("new C returns %p\n", c);
return 0;
}
When I run I get this:
new!
0x0->C()
new C returns 0x0
So I can make new return NULL but it still calls the constructor with a null 'this' pointer. Is there any way to write my own allocator that allocates memory, explicitly calls the c'tor if possible, then returns?
Thanks!
Returning a null pointer from an operator new means allocation failed, but only if the function is declared noexcept, otherwise the function most throw a std::bad_alloc (or something derived from it).
As it stands your program has undefined behavior, if you add noexcept you should find the constructor isn't called as the function now correctly signals that allocation failed.
static void* operator new(std::size_t sz) noexcept
[basic.stc.dynamic.allocation]
An allocation function shall be a class member function or a global function;[...]
[...] If an allocation function that has a non-throwing exception specification (15.4) fails to allocate storage, it shall return a null pointer. Any other allocation function that fails to allocate storage shall indicate failure only by throwing an exception (15.1) of a type that would match a handler (15.3) of type std::bad_alloc (18.6.2.1).

difference between return address of operator new[] and the actual address got for the array

I'm playing new operator overloading recently. I noticed a strange behavior when I overload new[] operator (the new operator for allocating arrays).
Here is my code:
#include <iostream>
using namespace std;
class Pool
{
public:
void* alloc(size_t size) {
return malloc(size);
}
};
class MyClass
{
public:
MyClass() {
cout<<"ctor called"<<endl;
}
~MyClass() {
cout<<"dtor called"<<endl;
}
void* operator new(size_t size) {
cout<<"new called, size: "<<size<<endl;
return (void*)malloc(size);
}
void* operator new[](size_t size) {
cout<<"new[] called, size: "<<size<<endl;
void* result = (void*)malloc(size);
cout<<"in new[]: "<<result<<endl;
return result;
}
void* operator new(size_t size, void* ptr) {
cout<<"new(ptr) called, size: "<<size<<endl;
return (void*)ptr;
}
void* operator new(size_t size, Pool& pool) {
cout<<"new(Pool) called, size: "<<size<<endl;
return (void*)pool.alloc(size);
}
void operator delete(void* ptr) {
cout<<"delete called, ptr: "<<ptr<<endl;
free(ptr);
}
void operator delete(void* ptr, size_t size) {
cout<<"delete called, ptr: "<<ptr<<", size: "<<size<<endl;
free(ptr);
}
void operator delete[](void* ptr) {
cout<<"delete[] called, ptr: "<<ptr<<endl;
free(ptr);
}
void operator delete[](void* ptr, size_t size) {
cout<<"delete[] called, ptr: "<<ptr<<", size: "<<size<<endl;
free(ptr);
}
uint32_t data;
};
int main() {
Pool pool;
cout<<"Pool"<<endl;
new Pool;
cout<<"MyClass"<<endl;
MyClass *ptr1, *ptr2, *ptr3;
ptr1 = new MyClass;
ptr2 = new MyClass[10]();
cout<<(void*)ptr2<<endl;
ptr3 = new(pool) MyClass;
delete ptr1;
delete[] ptr2;
delete ptr3;
return 0;
}
And the result (with gcc 64bit on OS X) is like:
Pool
MyClass
new called, size: 4
ctor called
new[] called, size: 48
in new[]: 0x7fa7f0403840
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
ctor called
0x7fa7f0403848
new(Pool) called, size: 4
ctor called
dtor called
delete called, ptr: 0x7fa7f0403830
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
dtor called
delete[] called, ptr: 0x7fa7f0403840
dtor called
delete called, ptr: 0x7fa7f0403870
I noticed three things: 1st, I asked to allocate 10 objects of 4 bytes in new[], but the actual request received by the function is 48 bytes. 2nd, apparently the first 8 bytes are used for other purpose: the actual address received by ptr2 is 8 bytes after the address returned by the new[] operator. 3rd, the address is also automatically translated (by going forward 8 bytes) in the overloaded delete[] function.
I also noticed that this behavior happens only when I explicitly implement the destructor. If I only use the default destructor, the 8 bytes are just gone.
Can anyone tell me what is happening behind this? What are the 8 bytes used for?
Thanks.
The array-new expression is allowed to call the array-operator-new with more space than needed for the array. All that's required is that the value of the array-new expression is a pointer to the first element in the array.
Practically, the extra space is needed to store information on how many elements need to be destroyed when the array is destroyed (sometimes called an "array cookie").
It's interesting to note that the actual amount of extra memory that is requested from the array-operator-new function is completely unknowable and may change with every call. This basically makes the array-placement-new expression defective and unusable.
Just for reference, the relevant clause is C++11 5.3.4/10:
A new-expression passes the amount of space requested to the allocation function as the first argument of type std::size_t. That argument shall be no less than the size of the object being created; it may be greater than the size of the object being created only if the object is an array.
The most interesting example follows just below:
new T[5] results in a call of operator new[](sizeof(T) * 5 + x), and
new(2,f) T[5] results in a call of operator new[](sizeof(T) * 5 + y, 2, f).
Here, x and y are non-negative unspecified values representing array allocation overhead; the result of the
new-expression will be offset by this amount from the value returned by operator new[]. This overhead may be applied in all array new-expressions, including those referencing the library function operator new[](std::size_t, void*) and other placement allocation functions. The amount of overhead may vary from one invocation of new to another.
You may be pleased to learn that the Itanium ABI has very sensible rules about array cookies; for example, none are needed for arrays of trivially-destructible objects.

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.

placement new signature

void someCode()
{
char memory[sizeof(Foo)];
void* place = memory;
Foo* f = new(place) Foo();
}
and the signature of new placement operator
void * operator new(size_t, void *p)
{
return p;
}
I don't get how a constructor could be bind to void *p since a constructor doesn't return any values ?
EDIT:
the following code for instance doesn't compile :
struct A{};
void f(void * p)
{
}
int main()
{
f(A());
std::cin.ignore();
}
The problem here is that C++ new is confusing:
there is the operator new, which you can overload and is in charge of allocating raw memory
there is the new expression (such as new A(5)) which under the covers first call the corresponding operator new overload and then performs the construction
Note that you have no say as to how the construction is performed: you supplied the type and the constructor parameters, the language does the rest, and there is no way to change this behavior.
Therefore, when you overload/override operator new, you are only affecting the raw memory allocation. The full syntax of the new expression can clear things up:
new (somepointer) A(5)
^~~~~~~~~~~~~ ^~~~
The first part is the list of arguments passed to operator new, on top of the size of the object (always passed). The second part corresponds to the constructor call. If there is no parameter to be passed to new (apart from the size which you don't control) then the first part may be omitted yielding the typical form new A(5).
You are free to overload new as much as you want, for example:
new (alignof(A)) A(5);
will call an operator new overload accepting a size_t as supplementary argument (representing the necessary alignment for the type):
void* operator new(size_t size, size_t alignment);
note: the first argument (size) is always there.
So, placement new is just a fancy overload in its own right:
void* operator new(size_t, void* p) { return p; }
There is not much interest in such an operator (it does nothing), however it helps maintaining a consistent syntax and allows you a way to specify where to build an object via using the new expression so that it is not necessary to create another syntax to allow such operation.
Constructor called after operator new executed. You posted not equivalent code. Equvalent would be
struct A
{
constructor (void* this);
}
int main ()
{
A a = A::constructor(operator new ());
}
It is not c++, just pceudocode
I think that the source of your confusion is an assumption that new(place) Foo(); is a single operation; it is not. Here is what's going on:
A placement new operator is called to allocate memory
A constructor is called to initialize the allocated memory
The first call needs to return the value (a void*). It is a block of memory suitable to store your object. The second call is a constructor. It gets the value from the placement new operator as its hidden this parameter, and performs its regular initialization tasks on it.

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.