2011-08-22 74 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中實例化。它可以很好地處理靜態鏈接對象,但我不知道爲什麼構造函數沒有被調用。 –