По причинам, которые я не хотел бы здесь углубляться, мне необходимо полностью распределить средства и освободить их в большой существующей кодовой базе, которая использует пользовательские operator new
а также operator delete
, С этой целью я переписываю (используя входной интерфейс Clang) каждый случай new X(...)
с new (allocate<X>()) X(...)
где реализация по умолчанию allocate<X>
призывает к классу operator new
, если он существует, или ::operator new
иначе. Я знаю, что это не 100% звук, но он «достаточно хорош» для кодовой базы, на которую я нацеливаюсь.
Теперь я пытаюсь ввести подобное поведение перехвата для delete
, но это сложнее, чем ожидалось, из-за странной природы виртуального operator delete
, От https://en.cppreference.com/w/cpp/memory/new/operator_delete:
Призыв к классу
T::operator delete
Полиморфный класс — единственный случай, когда статическая функция-член вызывается посредством динамической диспетчеризации.
Рассмотрим следующий пример:
struct A {
virtual ~A() { cout << "~A" << endl; }
static void operator delete(void* ptr) {
cout << "A::operator delete" << endl;
::operator delete(ptr);
}
};
struct B : public A {
virtual ~B() { cout << "~B" << endl; }
static void operator delete(void* ptr) {
cout << "B::operator delete" << endl;
::operator delete(ptr);
}
};
В идеале я хотел бы заменить каждое вхождение delete x
в кодовой базе с deleteWrapper(x)
, что эквивалентно delete x
по умолчанию, но я могу добавить дополнительные инструменты и специализировать его для определенных типов x
если нужно.
Я думал, что могу сделать что-то вроде следующего, чтобы достичь этого:
template <typename T>
void deleteWrapper(T* x) {
x->~T();
// The deallocation behavior here should "tweakable" for certain types
// of T, for example I might need different implementations for
// std::pair<int, int> and std::pair<std::string, int>
x->operator delete(x);
}
Но (кроме вызова неопределенного поведения) это не эквивалентно delete x
: С вышеуказанной иерархией типов, deleteWrapper(static_cast<A*>(new B))
звонки A::operator delete
вместо B::operator delete
, Есть ли способ вызвать правильную перегрузку, учитывая полиморфный указатель, без использования delete
?
Если есть решение, которое включает в себя определенное количество переписывания исходного кода, мне было бы интересно услышать об этом, так как я уже использую модифицированный лязг.
Задача ещё не решена.
Других решений пока нет …