how to define a static member in a template class

dennywang 2009-10-08 05:56:37

hi,下面是我在国外的论坛上面发的帖子,想到csdn上面也有很多高手,所以再发到此处寻求帮助

i have trouble to define a static member in a template, and i search from google, but didn't find any similar case, my case is a little complex, i paste the code below.

code in xxx.h

template <class T> class FreeListManager
{
public:
FreeListManager(int s=0);
~FreeListManager();
T* acquire();
void release(T*);

protected:
static list<T*> freeList;
static list<T*> usedList;
// We have size parameters separated from list, since
// size() function of list container is inefficient.

};

code in xxx.cpp

include "xxx.h"

template<class T> list<T*>
FreeListMaager<T>::freeList;
template<class T> list<T*>
FreeListManager<T>::usedList;

//there is no T defined


for the xxx.cpp file, actually, it is confused me a lot, and it seem to be not what i want, what is the type of the entry in freeList like after above definition? i got coredump when use the freeList.pushback. and i ever tried to define the two list static member like


template<class CLASSA> list<CLASSA*>
FreeListManager<CLASSA>::freeList;
template<class CLASSA> list<CLASSA*>
FreeListManager<CLASSA>::usedList;

template<class CLASSB> list<CLASSB*>
FreeListManager<CLASSB>::freeList;
template<class CLASSB> list<CLASSB*>
FreeListManager<CLASSB>::usedList;


i got redefinition for freeList and usedList error.
i was told FreeListManager<CLASSA> and FreeListManager<CLASSB> are totally two different class, why does the redefinition error come out?

i also try


list<CLASSA*> FreeListManager<CLASSA>::freeList;
list<CLASSA*> FreeListManager<CLASSA>::usedList;

list<CLASSB*> FreeListManager<CLASSB>::freeList;
list<CLASSB*> FreeListManager<CLASSB>::usedList;


i got too few template-parameter-lists error, the code can be compiled on gcc earlier version,

he code was download from opendiameter project, it can be compiled by very old version gcc complier.

but i found it cannot compliled by gcc-4.1.2

As i know, FreeListManager is a only template, and FreeListManager<CLASSA> is actual class, and FreeListManager<CLASSB> is another one, i want to define two static list member for both class,FreeListManager<CLASSA>::freeList, FreeListManager<CLASSB>::freeList, so the two static member should be not one instance, but two. Just like what i tested


template <class T> class FreeListManager
{
public:
static int counter;
};

template <class T> int FreeListManager<T>::counter=0;
//the following definition will report redefinition error, either
//template <CLASSA> int FreeListManager<CLASSA>::counter=0;
//template <CLASSB> int FreeListManager<CLASSB>::counter=0;
//i thought the complier only can initial the two static member once, and you can set other value later.

FreeListManager<CLASSA>::counter=2
FreeListManager<CLASSB>::counter=3

main()
{
printf("FreeListManager<CLASSA>::counter=%d\n",FreeListManager<CLASSA>::counter);
printf("FreeListManager<CLASSB>::counter=%d\n",FreeListManager<CLASSB>::counter);
}

##########################
the result is
FreeListManager<CLASSA>::counter=2
FreeListManager<CLASSB>::counter=3

so it seem there are two static variable FreeListManager<CLASSA> and FreeListManager<CLASSB>

can someone help me, really appreciate your help.
...全文
305 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
dennywang 2009-10-11
  • 打赏
  • 举报
回复
还有一个问题,我太了解“不要依赖全局变量的初始化顺序……”,我没有发现我的全局变量有什么依赖关系,为什么要受到初始化顺序的影响?
2009-10-11
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 dennywang 的回复:]
还有一个问题,我太了解“不要依赖全局变量的初始化顺序……”,我没有发现我的全局变量有什么依赖关系,为什么要受到初始化顺序的影响?
[/Quote]
仔细看看反汇编,
...
callq 0x400b9a <_ZN15FreeListManagerI6CLASSAEC1Ev>
...
callq 0x400960 <_ZNSt4listIP6CLASSASaIS1_EEC1Ev>
...
这里先调用 FreeListManager<CLASSA> 的构造函数,再调用 list<CLASSA*> 的……
dennywang 2009-10-10
  • 打赏
  • 举报
回复
呵呵,多谢hpsmouse这么认真的解答,我已经把那段全局变量workaround到了局部变量,然后就没有问题,继续去研究下一个问题了,看样子还是这个地方的什么原因导致的,我要自己再看一下子,如果还有问题的话,等我整理好了再问,thanks again.
2009-10-10
  • 打赏
  • 举报
回复
跟踪到的反汇编结果把我吓到了…………
Dump of assembler code for function _Z41__static_initialization_and_destruction_0ii:
0x0000000000400777 : push %rbp
0x0000000000400778 : mov %rsp,%rbp
0x000000000040077b : sub $0x10,%rsp
0x000000000040077f : mov %edi,-0x4(%rbp)
0x0000000000400782 : mov %esi,-0x8(%rbp)
0x0000000000400785 : cmpl $0x1,-0x4(%rbp)
0x0000000000400789 : jne 0x4007e4 <_Z41__static_initialization_and_destruction_0ii+109>
0x000000000040078b : cmpl $0xffff,-0x8(%rbp)
0x0000000000400792 : jne 0x4007e4 <_Z41__static_initialization_and_destruction_0ii+109>
0x0000000000400794 : mov $0x602060,%edi
0x0000000000400799 : callq 0x400b9a <_ZN15FreeListManagerI6CLASSAEC1Ev>
0x000000000040079e : mov $0x400a1a,%edi
0x00000000004007a3 : mov $0x602040,%edx
0x00000000004007a8 : mov $0x602060,%esi
0x00000000004007ad : callq 0x400630 <__cxa_atexit@plt>
0x00000000004007b2 : mov $0x602068,%eax
0x00000000004007b7 : movzbl (%rax),%eax
0x00000000004007ba : test %al,%al
0x00000000004007bc : jne 0x4007e4 <_Z41__static_initialization_and_destruction_0ii+109>
0x00000000004007be : mov $0x602068,%eax
0x00000000004007c3 : movb $0x1,(%rax)
0x00000000004007c6 : mov $0x602070,%edi
0x00000000004007cb : callq 0x400960 <_ZNSt4listIP6CLASSASaIS1_EEC1Ev>
0x00000000004007d0 : mov $0x400c5c,%edi
0x00000000004007d5 : mov $0x602040,%edx
0x00000000004007da : mov $0x602070,%esi
0x00000000004007df : callq 0x400630 <__cxa_atexit@plt>
0x00000000004007e4 : leaveq
0x00000000004007e5 : retq
End of assembler dump.

想起一句话:不要依赖全局变量的初始化顺序……
dennywang 2009-10-09
  • 打赏
  • 举报
回复
没错,你的代码能够顺利运行,我也比较了一下我的代码,然后修改了我的,发现有一个最重要的区别,就是我的
定义的变量时全局的,我也试了一下修改你的代码,改成

main.cpp:
#include "xxx.hpp"
typedef FreeListManager<CLASSA> mgr;

mgr aaa;

int main()
{
return 0;
}

编译通过,但是发生了同样的segment fault,一摸一样的地方,一摸一样的错误。
知道为什么吗,这个应该是关键了。多谢!!
2009-10-09
  • 打赏
  • 举报
回复
至少下面这段代码没事:
xxx.hpp:
#include <list>
using std::list;
template <class T> class FreeListManager
{
public:
FreeListManager();
~FreeListManager(){}
T* acquire();
void release(T*);

// protected:
static list<T*> freeList;
static list<T*> usedList;
// We have size parameters separated from list, since
// size() function of list container is inefficient.

};
template <class T> list<T*> FreeListManager <T>::freeList;
template <class T> FreeListManager<T>::FreeListManager()
{
freeList.push_back(new T);
}
class CLASSA
{
};

class CLASSB
{
};


main.cpp:
#include "xxx.hpp"
typedef FreeListManager<CLASSA> mgr;
int main()
{
mgr aaa;
return 0;
}
dennywang 2009-10-09
  • 打赏
  • 举报
回复
看了一下,template的export功能可以把template的实现和声明分开,但是我这个好像没有分开吧,我都放到xxx.h里面了啊
dennywang 2009-10-09
  • 打赏
  • 举报
回复
我不太知道什么叫export,我查一查资料,另外好像不是Freelist没有初始化,而是根本不存在。
fallening 2009-10-09
  • 打赏
  • 举报
回复
code in xxx.cpp

你的编译器支持export了?
但是我没有看到这个关键字出现在你的代码中啊
dennywang 2009-10-09
  • 打赏
  • 举报
回复
我在google上面查了一下,很有可能是这个Freelist根本就不存在,而且在我修改构造函数之后core就消失了

template <class T> FreeListManager <T> ()
{
list<T> Freelist;
Freelist.pushback(new T);
}

但是显然这个不是我想要的,但是估计能说明在前面的那个例子是因为Freelist没有初始化。
dennywang 2009-10-09
  • 打赏
  • 举报
回复
这样做确实可以编译通过,但是我发现它会引起一个segment fault coredump,

在xxx.h里面

template <class T> class FreeListManager
{

public:
FreeListManager();
private:
static list <T*> Freelist;

};

template <class T> list <T*> FreeListManager <T>::Freelist;

template <class T> FreeListManager<T> ()
{
Freelist.pushback(new T);
//from gdb, the core happened when doing pushback
}


在xxx.cpp里面
#include xxx.h

FreeListManager <AAAAvpContainerWithFlag> aaa;
//使这里初始化aaa的时候失败

***************************************************
#0 0x00000033c565b973 in std::_List_node_base::hook () from /usr/lib64/libstdc++.so.6
#1 0x00000000004166ae in std::list<AAAAvpContainerWithFlag*, std::allocator<AAAAvpContainerWithFlag*> >::_M_insert (this=0x639830, __position={_M_node = 0x639830}, __x=@0x7fffea29fcf8)
at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_list.h:1140
#2 0x00000000004166d9 in std::list<AAAAvpContainerWithFlag*, std::allocator<AAAAvpContainerWithFlag*> >::push_back (this=0x639830, __x=@0x7fffea29fcf8)
at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_list.h:761
#3 0x0000000000416a5e in FreeListManager (this=0x6397b0, s=100) at avp_container.h:97
#4 0x00000000004143e4 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535)
at avp_container.cxx:79
#5 0x00000000004145b5 in global constructors keyed to containerFLM () at avp_container.cxx:336
#6 0x0000000000427546 in __do_global_ctors_aux ()
#7 0x0000000000403a1b in _init ()
#8 0x00002acd11b1d858 in IDNodeImpl::getChildNodes() const::emptyNodeListCleanup () from ./libxerces-c1_7_0.so
#9 0x00000000004274c7 in __libc_csu_init ()
#10 0x00000033bfe1d84e in __libc_start_main () from /lib64/libc.so.6
#11 0x0000000000404469 in _start ()

AAAAvpContainerWithFlag 就是替换的T
2009-10-09
  • 打赏
  • 举报
回复
至少就我测试的结果来看,是的。
dennywang 2009-10-09
  • 打赏
  • 举报
回复
多谢,

也就是在xxx.h里面
template <class T> class FreeListManager
{
private:
static list<T*> Freelist;
};

template <class T> list<T*> FreeListManager<T>::Freelist;


然后在xxx.cpp里面

include xxx.h

FreeListManager<CLASSA> aaa;
FreeListManager<CLASSB> bbb;

这样,是不是aaa变量里面就会就会自动定义了静态的list<CLASSA*> Freelist,无须再去定义这个Freelist了,这个时候才会真正的分配空间,同样适用于bbb,
2009-10-08
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 dennywang 的回复:]
两个静态变量,分别在FreeListManager <CLASSA>和FreeListManager <CLASSB>两个类里面,我发现如果在template里面的一个int类型的就可以,但是是一个T类型的就不行,而且我也不能理解这样的定义到底是定义了什么,编译器怎么分配空间

template <class T> class FreeListManager
{
public:
static T counter;
};

template <class T> T FreeListManager <T>::counter;

//上面的这个如果算是定义的话,那么编译器怎么分配空间呢,也不知道T到底是什么类型啊。
[/Quote]
这个并不会导致编译器做什么实质性的事情,如果你只是把这个写在另一个 .cpp 里面,依旧是 undefined reference。
如果在头文件里写这个,那么每个相关的 .cpp 里面如果用到了这个类就会引发实例化,产生一份该变量的拷贝,连接的时候连接器再把重复的筛掉。
whg01 2009-10-08
  • 打赏
  • 举报
回复
编译器编译时,会用你指定的类型来替换模板中的T。即使用不同的类型,会生成不同的代码。
所以使用模板很容易使代码的体积快速膨胀。
模板和宏有一定的相似度。
dennywang 2009-10-08
  • 打赏
  • 举报
回复
两个静态变量,分别在FreeListManager <CLASSA>和FreeListManager <CLASSB>两个类里面,我发现如果在template里面的一个int类型的就可以,但是是一个T类型的就不行,而且我也不能理解这样的定义到底是定义了什么,编译器怎么分配空间

template <class T> class FreeListManager
{
public:
static T counter;
};

template<class T> T FreeListManager<T>::counter;

//上面的这个如果算是定义的话,那么编译器怎么分配空间呢,也不知道T到底是什么类型啊。
dennywang 2009-10-08
  • 打赏
  • 举报
回复
多谢大家

我是想有两个静态变量,分别在FreeListManager<CLASSA>和FreeListManager<CLASSB>两个类里面
wendll 2009-10-08
  • 打赏
  • 举报
回复
2楼说的没错,如果不是产生了两个不一样的类,将会给c++使用带来局限。
譬如单态模式(singleton)

#include <cstdlib>
#include <cctype>
#include <complex>
using namespace std;

template<class T>
class Singleton
{
public:
static T *Instance(); // Create an instance of the object
static T &ref_getSingleton(); // Get a reference to the object
static T *ptr_getSingleton(); // Get a pointer to the object

protected:
Singleton(); // notice that the constructor is NOT public

private:

static T *m_instance; // The actual object
};
template<class T>
T *Singleton<T>::m_instance = NULL ;

template<class T>
T *Singleton<T>::Instance()
{
if(m_instance == NULL)
return new Singleton() ;
else
return m_instance ;

}

class A
{} ;
class B
{} ;
int main()
{
Singleton<A> *a = Singleton<A>::Instance() ;
Singleton<B> *b = Singleton<B>::Instance() ;
system("PAUSE") ;
return 0 ;
}

在上面的情况下,如果静态成员变量或函数对不同的模板类是共享的,那将是多么混沌!


参考自:singleton patternhttp://www.google.com/url?q=http://gpwiki.org/index.php/Programming_Techniques:Singleton%23A_Singleton_Class_Template_in_C.2B.2B&usg=AFQjCNHSYIwq-NJUk-MhYTEPKVCg_NiDjA&ei=IdDNSvj5OsKOkQWmx5j-Aw&sa=X&oi=section_link&resnum=5&ct=legacy&ved=0CBUQygQ
2009-10-08
  • 打赏
  • 举报
回复
呼——试出来了!是不是这个效果?
template<> list<CLASSA*> FreeListManager<CLASSA>::freeList((list<CLASSA*>()));
2009-10-08
  • 打赏
  • 举报
回复
友情帮顶~
加载更多回复(2)

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧