首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么不调用我的新运算符

为什么不调用我的新运算符
EN

Stack Overflow用户
提问于 2009-06-28 10:48:04
回答 4查看 3.9K关注 0票数 8

我希望看到一个动态加载的库(使用dlopen等加载)。真正使用它自己的新an delete运算符,而不是调用程序中定义的这些运算符。所以我写了下面的library.cpp

代码语言:javascript
复制
#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;
    }
}

并使用以下命令进行编译

代码语言:javascript
复制
g++ -g -Wall -fPIC -shared library.cpp -o library.so

或者像受雇的俄罗斯人建议的那样尝试(但最终什么都没有改变)

代码语言:javascript
复制
g++ -g -Wall -fPIC -shared -Wl,-Bsymbolic library.cpp -o library.so

Base类只包含一个int值和一个get_value()函数来获取该值。在那之后,我写了这样的client.cpp

代码语言:javascript
复制
#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;
}

并使用以下命令进行编译

代码语言:javascript
复制
g++ -Wall -g -o client -ldl client.cpp

执行client时,我只得到一个"New of client called“和一个"Delete of client called”。即使我像使用俄语建议的那样,对库使用编译器开关-Bsymbolic。

现在:哪里出了问题?我以为共享库都在使用自己的new/delete,因此你必须提供在工厂旁边创建一个析构函数销毁的库代码。

补充问题:为什么需要destroy(Base* p)函数?如果这个函数只调用客户端的delete操作符,我也可以自己做,也就是在倒数第二行中用"delete a“代替destroy_module(a)。

我发现的答案:这个库还可以提供一个新的/delete-operator对。因此,如果我首先使用库的new,然后使用客户端的delete,那么我可能会陷入一个陷阱。遗憾的是,直到现在我还没有看到我的库使用它自己的新的或删除的……因此,最初的问题仍然没有得到回答。

补充:我只是指Linux平台。

编辑:重要的部分在对受雇俄语答案的评论中。因此,我给出的主要线索简而言之:如果有人这样调用gcc

代码语言:javascript
复制
g++ -Wall -g -fPIC -shared library.cpp -o library.so -Wl,-Bsymbolic

该库将使用它自己的new/delete操作符。否则结果

代码语言:javascript
复制
g++ -Wall -g -fPIC -shared library.cpp -o library.so

在使用调用程序的new/delete操作符的库中。感谢受雇的俄罗斯人!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-06-29 05:50:40

问题在于,在大多数UNIX平台上(与Win32AIX不同),默认情况下,所有符号引用都绑定到运行时加载程序可见的符号的第一个定义。

如果在主a.out中定义'operator new',所有内容都将绑定到该定义(如Neil Butterworth的示例所示),因为a.out是第一个图像运行时加载器搜索。

如果您在一个在libC.so之后加载的库中定义它(如果您使用GCC,则在libstdc++.so之后加载),那么您的定义将永远不会被使用。由于您是在程序启动后对库进行dlopen()操作,因此libC在此时已经加载,并且您的库是运行时加载程序将搜索的最后一个库;因此,您将失败。

ELF平台上,您可以使用-Bsymbolic更改默认行为。在Linux上的man ld上:

代码语言:javascript
复制
 -Bsymbolic
   When creating a shared library, bind references to global symbols
   to the definition within the shared library, if any. Normally, it
   is possible for a program linked against a shared library to override
   the  definition within the shared library. This option is only meaningful
   on ELF platforms which support shared libraries.

请注意,-Bsymbolic是一个链接器标志,而不是编译器标志。如果使用g++,则必须将标志传递给链接器,如下所示:

代码语言:javascript
复制
  g++ -fPIC -shared library.cpp -o library.so -Wl,-Bsymbolic
票数 11
EN

Stack Overflow用户

发布于 2009-06-28 10:55:58

下面的代码按预期工作。您是否期望您的动态库代码使用您提供的new/delete?我想你会失望的。

代码语言:javascript
复制
#include <memory>
#include <cstdio>
#include <cstdlib>
using namespace std;;

void* operator new(size_t size) {
        std::printf("New...\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...\n");
        std::free(p);
}

int main() {
    int * p = new int(42);
    delete p;
}
票数 1
EN

Stack Overflow用户

发布于 2009-10-06 22:57:17

调查RTLD_DEEPBIND

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1054697

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档