Я хотел видеть, что динамически загружаемая библиотека (загруженная с помощью dlopen и т. Д.) Действительно использует свои новые операторы удаления, а не те, которые определены в вызывающей программе. Поэтому я написал следующую библиотеку .cpp
#include <exception>
#include <new>
#include <cstdlib>
#include <cstdio>
#include "base.hpp"
void* operator new(size_t size) {
std::printf("New of library called\n");
void *p=std::malloc(size);
if (p == 0) // did malloc succeed?
throw std::bad_alloc(); // ANSI/ISO compliant behavior
return p;
}
void operator delete(void* p) {
std::printf("Delete of library called\n");
std::free(p);
}
class Derived : public Base {
public:
Derived() : Base(10) { }
};
extern "C" {
Base* create() {
return new Derived;
}
void destroy(Base* p) {
delete p;
}
}
и скомпилировал его с
g++ -g -Wall -fPIC -shared library.cpp -o library.so
или как занятый русский предложил попробовать (но в итоге ничего не изменилось)
g++ -g -Wall -fPIC -shared -Wl,-Bsymbolic library.cpp -o library.so
Класс Base содержит только значение типа int и функцию get_value () для получения этого значения. После этого я написал client.cpp вот так
#include <exception>
#include <new>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <dlfcn.h>
#include "base.hpp"
void* operator new(size_t size) {
std::printf("New of client called\n");
void *p=std::malloc(size);
if (p == 0) // did malloc succeed?
throw std::bad_alloc(); // ANSI/ISO compliant behavior
return p;
}
void operator delete(void* p) {
std::printf("Delete of client called\n");
std::free(p);
}
typedef Base* create_module_t();
typedef void destroy_module_t(Base *);
int main() {
void* handle = dlopen("./library.so",
RTLD_LAZY);
if (handle == NULL) {
std::cout << dlerror() << std::endl;
return 1;
}
create_module_t* create_module = NULL;
void* func = dlsym(handle, "create");
if (func == NULL) {
std::cout << dlerror() << std::endl;
return 1;
} else create_module = (create_module_t *)func;
destroy_module_t* destroy_module = NULL;
func = dlsym(handle, "destroy");
if (func == NULL) {
std::cout << dlerror() << std::endl;
return 1;
} else destroy_module = (destroy_module_t *)func;
Base* a = create_module();
std::cout << "Value: " << a->get_value() << std::endl;
destroy_module(a);
return 0;
}
и скомпилировал его с
g++ -Wall -g -o client -ldl client.cpp
Выполнение клиента Я получаю только «Новый клиент называется» и «Удалить клиент называется». Даже если я использую переключатель компилятора -Bsymbolic для библиотеки, как предложил Employed Russian.
Теперь: что пошло не так? Я думал, что разделяемые библиотеки используют свои собственные новые / удаления, и поэтому вы должны предоставить рядом с фабрикой создать деструктор уничтожить в коде библиотеки.
Дополнительный вопрос: зачем мне функция destroy (Base * p)? Если эта функция вызывает только оператор удаления клиента, я мог бы сделать это сам, то есть «удалить a» вместо destroy_module (a) в следующей за последней строкой.
Ответ, который я нашел: Библиотека также может предоставить новую пару / оператор удаления. Так что, если я использую сначала новую библиотеку, а затем клиентское удаление, я, вероятно, попаду в ловушку. К сожалению, до сих пор я никогда не видел свою библиотеку, использующую ее новую или удаленную ... Так что на оригинальный вопрос до сих пор нет ответа.
Дополнение: я имею в виду только платформу Linux.
Редактировать: Важные части находятся в комментариях к Ответу занятого русского. Итак, я даю основную подсказку в двух словах: если кто-то так называет gcc
g++ -Wall -g -fPIC -shared library.cpp -o library.so -Wl,-Bsymbolic
библиотека будет использовать собственные операторы new / delete. В противном случае результаты
g++ -Wall -g -fPIC -shared library.cpp -o library.so
в библиотеке, использующей операторы new / delete вызывающей программы. Спасибо занятым русским!