问题
We're trying to overload the delete[] operator with specific arguments. Which is the right way to call it? We use the GNU compiler and obtain compiler errors with all of these samples:
#include<memory>
using namespace std;
typedef unsigned int P;
struct A{
static allocator<A>m;
P p;
void*operator new[](size_t s){return m.allocate(s);}
void operator delete[](void*p,int s){m.deallocate((A*)p,s);}
void operator delete[](void*p,size_t t,int s){m.deallocate((A*)p,s);}
};
int main(){
A*a=new A[10];
//delete (5) []a; //expected ',' before 'a'
//delete[5]a; //expected ';' before ']' token
//delete[] (5) a; //type ‘int’ argument given to ‘delete’, expected
//delete[]a (5); //a’ cannot be used as a function
//delete[]((int)5)a; //type ‘int’ argument given to ‘delete’, expected pointer
//delete[]a((int)5); //‘a’ cannot be used as a function
return 0;
}
回答1:
There's no "syntactic sugar" for this kind of placement deleter.
A placement deleter (like what you've declared) is only called when a constructor that was called by a placement new, throws an exception.
Then the program will call the matching placement deleter (same signature) and try to free the customly allocated memory.
If you still want to call this method, you'll have to call the operator manually:
A::operator delete[](a, 5);
There's a nice example of how it works here: http://en.cppreference.com/w/cpp/memory/new/operator_delete
Notice the exception in the class destructor (the delete operator is called after the exception is triggered):
#include <stdexcept>
#include <iostream>
struct X {
X() { throw std::runtime_error(""); }
// custom placement new
static void* operator new(std::size_t sz, bool b) {
std::cout << "custom placement new called, b = " << b << '\n';
return ::operator new(sz);
}
// custom placement delete
static void operator delete(void* ptr, bool b)
{
std::cout << "custom placement delete called, b = " << b << '\n';
::operator delete(ptr);
}
};
int main() {
try {
X* p1 = new (true) X;
} catch(const std::exception&) { }
}
回答2:
TL;DR: custom placement deleters are only called if a constructor of the object throws and can't be called without an explicit operator call e.g.
Class::operator delete[](a, 10, etc..);
Destructors will NOT be called anyway (another task you'll have to do manually yourself).
Details:
From cppreference
Overloads of operator delete and operator delete[] with additional user-defined parameters ("placement forms", version 11-12) may be declared at global scope as usual, and are called by the matching placement forms of new-expressions if a constructor of the object that is being allocated throws an exception.
The standard library placement forms of operator delete (9-10) cannot be replaced and can only be customized if the placement new-expression did not use the ::new syntax, by providing a class-specific placement delete (17,18) with matching signature: void T::operator delete(void*, void*) or void T::operator delete[](void*, void*).
struct A{
void* operator new[](std::size_t s){
cout << "allocation 1" << endl;
...
return ptr;
}
void* operator new[](std::size_t s, int){
cout << "allocation 2" << endl;
...
return ptr;
}
void operator delete[](void* s, std::size_t ){
cout << "deallocate 1" << endl;
...
}
void operator delete[](void* s, std::size_t , int ){
cout << "deallocate 2" << endl;
...
}
};
int main(){
A*a=new A[10];
delete[] a;
A*b=new(5) A[10];
A::operator delete[](b,sizeof(b)/sizeof(A*),5); // You'll have to call it manually!
return 0;
}
来源:https://stackoverflow.com/questions/26078560/overload-delete-operator-with-specific-arguments