【发布时间】:2010-11-06 11:36:03
【问题描述】:
我想看看一个动态加载的库(用 dlopen 等加载)真的使用它自己的新删除操作符,而不是调用程序中定义的这些操作符。于是我写了如下library.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
执行客户端我只得到一个“新的客户端调用”和一个“删除客户端调用”。即使我像 Employed Russian 建议的那样为库使用编译器开关 -Bsymbolic。
现在:出了什么问题?我认为共享库正在使用他们自己的 new/delete,因此您必须在工厂旁边提供在库代码中创建析构函数销毁。
补充问题:为什么需要destroy(Base* p)函数?如果这个函数只调用客户端的delete-operator,我也可以自己做,即“delete a”而不是最后一行的destroy_module(a)。
我找到的答案:该库还可以提供一个新/删除操作符对。因此,如果我首先使用库的新功能,然后使用客户端的删除功能,我可能会陷入陷阱。可悲的是,直到现在我从未见过我的图书馆使用它自己的新的或删除的......所以最初的问题仍然没有得到回答。
补充:我只指Linux平台。
编辑:重要部分在就业俄罗斯人答案的 cmets 中。所以我简单地给出主要线索:如果有人以这种方式调用 gcc
g++ -Wall -g -fPIC -shared library.cpp -o library.so -Wl,-Bsymbolic
库将使用它自己的新/删除操作符。否则结果
g++ -Wall -g -fPIC -shared library.cpp -o library.so
在使用调用程序的 new/delete 运算符的库中。感谢受雇的俄罗斯人!
【问题讨论】:
-
你是如何“在我的测试程序中使用它”的?你试过 LD_PRELOAD 了吗?
-
我在我的帖子中更准确地说明了“在我的测试程序中使用它”。但是我还是不明白你说的 LD_PRELOAD 是什么意思。
-
为什么这么难过?这不是证明是在使用自己的 new 和 delete 吗?这就是你要测试的不是吗?
-
我认为您需要更新您的原始问题以避免我在下面看到的混淆。清楚地表明新/删除存在于您的 .dll 中,并显示您的“创建”功能的实现(我想象它只是在某些东西上调用“新”)。另外,你在什么平台上运行?如果这是我所怀疑的, printf 将不起作用。
-
好的,我编辑了我的问题并添加了更多信息。我希望现在更清楚了。
标签: c++ g++ overriding allocation