2012-07-26 81 views
5

我有一个多线程的应用程序。 我在一个共享库中声明一个具有静态成员的类。一个静态成员的两个实例,怎么可能?

从不同库中打印来自不同线程的成员地址会显示不同的结果。

//声明

template <class OBJECT> 
struct Container 
{ 
    static int m_member; 
}; 

template <class OBJECT> 
int Container<OBJECT>::m_member; 

//打印

cout << (void*) &Container<int>::m_member << endl; 

怎么可能?

+0

当你从不同的库中说不同的线程时,你的意思是你有一个进程有几个线程访问该成员?当我没有记错的时候,我听说共享库是按每个进程实例化的,所以每个进程都有它自己的版本(不会干扰其他进程)。 – Nobody 2012-07-26 09:26:28

+1

你如何链接“共享库”? – 2012-07-26 09:26:43

+0

这是一个有多个线程的进程。该成员在头文件中定义(在我的真实代码容器是模板化的),但我很确定这不是问题。 – Ezra 2012-07-26 09:28:38

回答

4

如果你有不同的库,(我猜测不同的动态库),那么你可能会重复代码和静态变量。

确切的细节将取决于您使用的特定动态库技术。我会说,例如,在Windows DLL中,您将重复代码和变量,但在Linux SO中,您不会。

无论如何,您应该提供有关操作系统和项目布局的更多细节。

UPDATE:啊,但你的班级是一个模板!共享库中的模板实例化是一个奇怪的野兽!为了确保在整个过程中只使用一个类的副本,必须显式实例化模板并确保此实例化在SO中导出,并且从客户端代码中使用它。细节与编译器有所不同,但你可以检查如何std::string完成,例如:

在头文件:

namespace std 
{ 
    extern template class basic_string<wchar_t>; 
} 

在库的源:

namespace std 
{ 
    template class basic_string<wchar_t>; 
} 

当然,你需要事先知道你的模板需要哪些实例化。显然,SO不能导出使用它不知道的类型的实例。

UPDATE:啊,但你必须instantating模板两个不同的库......那么,如果这两个库定义明确的实例为extern共享ELF魔都应该实例合并成一个。

继续更新:玩模板和共享对象后,它通常只是工作。我现在的猜测是你正在编译-fvisibility=hidden或类似的库。如果是这样的话,这将是足够的只是写:

template <class OBJECT> 
struct __attribute__((visibility("default"))) Container 
{ 
    static int m_member; 
}; 

为了使模板的特化进入动态符号表,从而避免重复。

+0

我使用Linux CentOS,因此是。据我所知,应该只有一个Container :: m_member的实例。 – Ezra 2012-07-26 09:33:18

+0

+1。但是,我已经尝试了您的建议,仍然得到两个实例。如果这可能会提示:我看到的地址长度不同:0x61bdb0,0x2aaaab92d5b0。我的机器是64位。 – Ezra 2012-07-26 21:34:58

+0

@Ezra:我已经做了一个例子,并能够获得两个结果(相同的地址或不同的地址)只是与可见性选项一起玩。你真的应该发布一些可编译的代码和编译器命令来重现你的问题。 – rodrigo 2012-07-26 22:41:10

相关问题