2011-08-22 76 views
0

我现在有点困惑。昨天我有未定义的符号,即使我用g ++的-rdynamic。但是现在我没有任何错误,这更令人不安。使用共享对象中的应用程序的对象

为了解释一下我的情况,我想做一些类似于共享对象的插件。我还没有决定哪个是最好的方法。

A)我的共享对象都有一个称为寄存器的函数,它将被一个参数调用。这将是一个插件管理器。

B)我的共享对象将定义一个类,并将在加载时创建该类的实例。在该类的构造函数中,它将尝试从应用程序获取静态单例并自动注册。

据我所知,迄今为止我的第一次尝试并不是那么棒。

的main.cpp

#include "main.hpp" 
#include <iostream> 
#include <cstdio> 
#include <dlfcn.h> 

int S::shared = 0; 

int main(int argc, char** argv){ 
    std::cout << "In main -> " << S::shared << "\n"; 

    void* triangle = dlopen("./libtwo.so", RTLD_LAZY); 

    if(triangle == NULL){ 
     std::cout << "Error while loading so file\n" << dlerror() << "\n"; 
    } 

    std::cout << "In main -> " << S::shared << "\n" << triangle; 
    return 0; 
} 

main.hpp

class S { 
    public: 
    static int shared; 

    S(){ 
     S::shared = 0; 
    }; 
}; 

two.cpp

#include "main.hpp" 
#include <iostream> 

class MyObject { 
    public: 
    MyObject(){ 
     std::cout << "In two -> " << S::shared << "\n"; 
    } 
}; 

MyObject t(); 

在该试样S ::共享是静态对象我想共享。对于这个简单的测试,我只使用一个int,但在未来它将是一个类的实例。

我唯一的情况A)的尝试是一个段错误...我真的不知道我错过了什么。

//结果至今(今天)

[email protected]:~/dev/WebDesign/Scproci$ scons -Q 
g++ -o two.os -c -fPIC two.cpp 
g++ -o libtwo.so -shared two.os 
g++ -o main.o -c -fPIC main.cpp 
g++ -o main -Wl,--export-dynamic main.o -ldl 
[email protected]:~/dev/WebDesign/Scproci$ ./main 
In main -> 0 
In main -> 0 
+0

基于显示的内容,您仅显示第二种方法的代码,其行为与预期相同。 – diverscuba23

+0

为什么不显示“在两个 - > 0”? –

+0

未定义的符号会发生,因为S :: shared是在main.cpp中定义的,但是当链接libtwo.so时,您没有在其中定义main.o。 – Flame

回答

1
#include "main.hpp" 
#include <iostream> 

class MyObject {  
    public:  
     MyObject(){   
      std::cout << "In two -> " << S::shared << "\n";  
     } 
}; 

MyObject* t; 

__attribute__((constructor)) 
void init_two() 
{ 
    t = new MyObject(); 
} 

__attribute__((destructor)) 
void uninit_two() 
{ 
    delete t; 
} 

这应该会产生所期望的。使用指针是因为在共享对象中显式处理它们更容易,因为常规初始化不会自动发生。如果您不想使用指针为您的类提供显式初始化并在共享库初始化函数中调用它。

*编辑*

我做了一些额外的实验,看来,如果你使用的是默认的构造函数,隐式地使用它,它就会被调用,如果您使用非默认的构造函数,然后作为正常。

,所以你可以改变你的:

MyObject t(); 

呼吁:

MyObject t; 

,它西港岛线没有被定义明确的初始化函数工作。

class MyObject { 
public: 
    MyObject() { /* as before */ }; 
    MyObject(int val) 
    { 
     S::shared = val; 
     std::cout << "In two -> " << S::shared << "\n"; 
    } 
}; 

MyObject t(10); 

看来,编译器会很困惑至于是否为MyObject吨();是全局范围的变量声明或函数声明,并将其视为函数声明。

+0

它确实有效。 –

+0

我还没有将它标记为答案。看到我对这个问题的评论。尽管如此。这可能是最好的方式。关于如何加载共享对象的定义看起来非常模糊,可能依赖于一个编译器与另一个编译器。明确定义加载和卸载函数可能是最安全的事情。 –

+0

我发现了相同的结果。 MyObject t()将不起作用,但隐式将起作用。这是一个非常有趣的案例。 –

0

立即跳到我的问题是,你必须分开链接单元。静态类成员只是包含在该类的名称空间中的全局变量。

现在,如果你有两个链接单元,比如说你的主程序和共享对象,他们很有可能拥有一个全局的foo,它们将是不同的值。另外,为什么two.cpp中t的静态初始化没有在共享对象中运行尚不清楚,它可能并不保证在共享对象的某些类型的主函数之前发生。

+0

不会有两个foo,因为在我的例子中,S :: shared仅在main.cpp中实例化。它可以很好地处理静态链接对象,但我不知道为什么构造函数没有被调用。 –