Reputation:
Here is from 3.7.4.2 N3797:
The global operator delete[] with exactly two parameters, the second of which has type std::size_t, is a usual deallocation function.37
37) This deallocation function precludes use of an allocation function void operator new(std::size_t, std::size_t) as a placement allocation function
This note is not clear for me. I would like to look at the real example of that preclusion. Compiler will throw a warning or we have a runtime error? I've been trying to write something like the following:
using std::cout;
struct A
{
int a;
A(){ a = 5; }
void * operator new(std::size_t t, std::size_t)
{
void *p = ::operator new(t);
return p;
}
};
int main(){ }
And I have no idea about example which reflects this preclusion. Could you help me provided one?
Upvotes: 0
Views: 235
Reputation: 1461
If the constructor throws an exception during a new call, the similarly declared delete with the same parameters will be called. For this reason, placement new and delete should always be declared in matching pairs.
In this case, the delete will have the same signature as the array delete and the compiler will not be able to choose between them.
Edited to add sample code and output.
Your code did not implement the global array placement new that is forbidden:
void * operator new( size_t bytes, size_t )
This program will illustrate how the global new and delete are called.
#include <stdint.h>
#include <malloc.h>
#include <iostream>
#include <stdexcept>
using namespace std;
struct A
{
int a;
A( void )
: a( 1 )
{
cout << __LINE__ << " : A::A()" << endl;
throw logic_error( "That is .. illogical" );
}
};
// Placement new with size_t parameter
void * operator new( size_t bytes, size_t )
{
cout << __LINE__ << " : void * A::operator new( size_t bytes = " << bytes << ", size_t )";
void *p = malloc( bytes );
cout << " -> " << p << endl;
return p;
}
// C++11 : Array placement delete with size_t parameter
// C++14 : Array delete
void operator delete( void *p, std::size_t n )
{
cout << __LINE__ << " : void A::operator delete( void *p = " << p << ", size_t n = " << n << " )" << endl;
if (p)
free( p );
}
// Non-array new
void * operator new( size_t bytes )
{
cout << __LINE__ << " : void * A::operator new( size_t bytes = " << bytes << " )";
void *p = malloc( bytes );
cout << " -> " << p << endl;
return p;
}
// Non-array delete
void operator delete( void *p ) noexcept
{
cout << __LINE__ << " : void A::operator delete( void *p = " << p << " )" << endl;
if (p)
free( p );
}
// Array new
void * operator new[]( size_t bytes )
{
cout << __LINE__ << " : void * A::operator new[]( size_t bytes = " << bytes << " )";
void *p = malloc( bytes );
cout << " -> " << p << endl;
return p;
}
// Array placement new with size_t parameter
void * operator new[]( size_t bytes, size_t n )
{
cout << __LINE__ << " : void * A::operator new[]( size_t bytes = " << bytes << ", size_t n = " << n << " )";
void *p = malloc( bytes );
cout << " -> " << p << endl;
return p;
}
// C++11 : Array placement delete with size_t parameter
// C++14 : Array delete
void operator delete[]( void *p, std::size_t n )
{
cout << __LINE__ << " : void A::operator delete[]( void *p = " << p << ", size_t n = " << n << " )" << endl;
if (p)
free( p );
}
int main( int, char ** )
{
A *p = nullptr;
#if 1
try
{
cout << __LINE__ << " : ===== Array placement new allocate with size_t parameter. =====" << endl;
p = new( (size_t)4 ) A[ 3 ];
cout << __LINE__ << " : ===== Array placement new succeeded. =====" << endl;
}
catch (...)
{
}
cout << __LINE__ << " : ===== Array placement delete. =====" << endl;
delete[] p;
p = nullptr;
#endif
try
{
cout << __LINE__ << " : ===== Array new. =====" << endl;
p = new A[ 3 ];
cout << __LINE__ << " : ===== Array new succeeded. =====" << endl;
}
catch (...)
{
}
cout << __LINE__ << " : ===== Array delete. =====" << endl;
delete[] p;
p = nullptr;
cout << __LINE__ << " : ===== Complete. =====" << endl;
return 0;
}
Compiling with clang 3.4.2 for C++11 gives this result:
$ clang++ --std=c++11 -o replace_new main.cpp && ./replace_new
88 : ===== Array placement new allocate with size_t parameter. =====
66 : void * A::operator new[]( size_t bytes = 12, size_t n = 4 ) -> 0x80048358
14 : A::A()
40 : void * A::operator new( size_t bytes = 33 ) -> 0x800483d8
76 : void A::operator delete[]( void *p = 0x80048358, size_t n = 4 )
49 : void A::operator delete( void *p = 0x800483d8 )
97 : ===== Array placement delete. =====
105 : ===== Array new. =====
57 : void * A::operator new[]( size_t bytes = 12 ) -> 0x80048358
14 : A::A()
40 : void * A::operator new( size_t bytes = 33 ) -> 0x800483d8
49 : void A::operator delete( void *p = 0x80048358 )
49 : void A::operator delete( void *p = 0x800483d8 )
114 : ===== Array delete. =====
118 : ===== Complete. =====
The allocation of 33 bytes is the exception. The exception and the array are both deleted with the same delete function.
Compiling with C++14 rules gives this result:
$ clang++ --std=c++1y -o replace_new main.cpp && ./replace_new
main.cpp:89:17: error: 'new' expression with placement arguments refers to non-placement 'operator delete'
p = new( (size_t)4 ) A[ 3 ];
^ ~~~~~~~~~
main.cpp:74:10: note: 'operator delete[]' declared here
void operator delete[]( void *p, std::size_t n )
^
1 error generated.
Disabling the invalid section and compiling with C++14 rules gives this result:
$ clang++ --std=c++1y -o replace_new main.cpp && ./replace_new
105 : ===== Array new. =====
57 : void * A::operator new[]( size_t bytes = 12 ) -> 0x80048358
14 : A::A()
40 : void * A::operator new( size_t bytes = 33 ) -> 0x800483d8
76 : void A::operator delete[]( void *p = 0x80048358, size_t n = 12 )
49 : void A::operator delete( void *p = 0x800483d8 )
114 : ===== Array delete. =====
118 : ===== Complete. =====
Notice that the array is now deleted with a different delete function. It is the same delete function at line 76 that deleted the array placement new when compiled as C++11.
Upvotes: 1