模版 在代码里有几个 副本的问题

combobox2013 2013-06-17 06:56:37
类模版中的静态变量和静态成员函数和普通函数的问题


template<typename T>
class Test
{
T val;
public:
static void Fun(){}

void Fun2(){}
};


Test<int> obj1;
obj1.Fun();
obj1.Fun2();

Test<int>obj2;
obj2.Fun();
obj2.Fun();


问题1: 对于普通函数,Fun2在代码里有几个副本?

是否是共用的? 因为都是用int去实例化!!1


如果不是同一种类型实例化,又该如何?

问题2:

对于 静态函数 Fun而言, 对于同一种类型有几个副本, 不同的类型又有几个?




...全文
155 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
ri_aje 2013-06-18
  • 打赏
  • 举报
回复
引用 4 楼 combobox2013 的回复:
[quote=引用 3 楼 ri_aje 的回复:] 楼主只要把相应的概念对普通的类理解透彻,然后再记住类模板实例化以后就变成普通的类,就应该能够推理出它们在类模板情况下的性质了。
引用 2 楼 u010936098 的回复:
在用相同模板参数进行实例化时,如果函数足够简单,并且:在类定义内定义或有inline声明或编译器进行了优化,这时函数就是内联函数,会直接把代码插入到调用处,但取地址的话是同一个地址。如果函数不能内联,那就只有一个。 当用不同模板参数进行实例化时,每个实例生成一个“副本”。 静态成员函数与非静态成员函数都一样,事实上普通成员函数只是比静态成员函数多了一个隐含的参数——this。
参考 第15楼 http://bbs.csdn.net/topics/390485405?page=1#post-394797026 这个帖子,我简答的说一下,是一个单例类, 一个友元模版类, 模版类有getinstance函数, 单例类的构造,拷贝等函数均是私有的。 代码为: 模版类 template <class T> class Singleton { protected: Singleton(){} public: static T& Instance() { static T instance; return instance; } }; 目标单例类 class ExampleSingleton //: public Singleton<ExampleSingleton> { // so that Singleton<ExampleSingleton> can access the // protected constructor friend class Singleton<ExampleSingleton>; //注意友原 protected: ExampleSingleton(){} public: // This class's real functionalities void Write(){printf("Hello, World!");} }; Singleton<ExampleSingleton>::Instance().Write(); 每一个使用Singleton<ExampleSingleton>的地方都可能会生成一个Instance() 因为Singleton<ExampleSingleton>和ExampleSingleton毫无关系; 这带颜色的文字,是一个网友说的, 我问其什么原因,其回答: C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板; 那么静态变量或者静态函数,就会在同一个程序里有又多个版本,因为静态变量或者静态函数是内部连接的,同一程序可以出现多个同名变量或者函数假设这个程序分成N个部分编译,每一份都分别实例化模板的话,就会有N个单例的实例,关键是模板是使用时实例化的,除非预先实例化,并编译好模板,否则,就会出现多份的单例的实例。 所以就会出现这种递归定义的情况,用来解决这个问题。 也就说, 其认为我提供的这种友元写法,是有漏洞的, 如何解决呢? 采用递归定义即可解决。 根本原因是: ]C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板;有多个副本。 所以,我才发这个帖子 [/quote] 我觉得他说的问题不存在,在某些非常 tricky 的情况下,可能存在问题,但是同样的情况下,crtp 也存在同样的问题,没什么太大优势可言。归根结底是由于 singleton 模式和 c++ 模板的精神有点背道而驰造成的,和友元或 crtp 的写法关系不大。不过你那种友元的写法确实比较费手。
橡木疙瘩 2013-06-18
  • 打赏
  • 举报
回复
这种说法是对老的编译器是正确的,但符合标准的编译器会处理这个问题。目前多数编译器会在每个调用该模板的cpp文件中为函数生成一份副本,但在链接时会把它们合并,最终代码中只有一个版本。并且,由于静态局部变量的存在,编译器将不会对它进行inline化。 要注意类的静态成员与C的全局静态变量/全局静态函数是完全不一样的,C的全局静态标识符是模块内部连接的,会在每个使用它的模块中生成一个副本,但类的静态成员不是这个语义。事实上,虽然C++中依然支持全局静态变量/函数,但只是为了保持对旧代码的兼容,标准中并不提倡继续使用这一特性,而是建议使用匿名namespace代替它。因些,如果某个编译器把全局静态函数的所有副本合并成了一个,也是很有可能出现的情况。
ri_aje 2013-06-18
  • 打赏
  • 举报
回复
引用 12 楼 combobox2013 的回复:
[quote=引用 11 楼 ri_aje 的回复:] [quote=引用 4 楼 combobox2013 的回复:] [quote=引用 3 楼 ri_aje 的回复:] 楼主只要把相应的概念对普通的类理解透彻,然后再记住类模板实例化以后就变成普通的类,就应该能够推理出它们在类模板情况下的性质了。
引用 2 楼 u010936098 的回复:
在用相同模板参数进行实例化时,如果函数足够简单,并且:在类定义内定义或有inline声明或编译器进行了优化,这时函数就是内联函数,会直接把代码插入到调用处,但取地址的话是同一个地址。如果函数不能内联,那就只有一个。 当用不同模板参数进行实例化时,每个实例生成一个“副本”。 静态成员函数与非静态成员函数都一样,事实上普通成员函数只是比静态成员函数多了一个隐含的参数——this。
参考 第15楼 http://bbs.csdn.net/topics/390485405?page=1#post-394797026 这个帖子,我简答的说一下,是一个单例类, 一个友元模版类, 模版类有getinstance函数, 单例类的构造,拷贝等函数均是私有的。 代码为: 模版类 template <class T> class Singleton { protected: Singleton(){} public: static T& Instance() { static T instance; return instance; } }; 目标单例类 class ExampleSingleton //: public Singleton<ExampleSingleton> { // so that Singleton<ExampleSingleton> can access the // protected constructor friend class Singleton<ExampleSingleton>; //注意友原 protected: ExampleSingleton(){} public: // This class's real functionalities void Write(){printf("Hello, World!");} }; Singleton<ExampleSingleton>::Instance().Write(); 每一个使用Singleton<ExampleSingleton>的地方都可能会生成一个Instance() 因为Singleton<ExampleSingleton>和ExampleSingleton毫无关系; 这带颜色的文字,是一个网友说的, 我问其什么原因,其回答: C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板; 那么静态变量或者静态函数,就会在同一个程序里有又多个版本,因为静态变量或者静态函数是内部连接的,同一程序可以出现多个同名变量或者函数假设这个程序分成N个部分编译,每一份都分别实例化模板的话,就会有N个单例的实例,关键是模板是使用时实例化的,除非预先实例化,并编译好模板,否则,就会出现多份的单例的实例。 所以就会出现这种递归定义的情况,用来解决这个问题。 也就说, 其认为我提供的这种友元写法,是有漏洞的, 如何解决呢? 采用递归定义即可解决。 根本原因是: ]C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板;有多个副本。 所以,我才发这个帖子 [/quote] 我觉得他说的问题不存在,在某些非常 tricky 的情况下,可能存在问题,但是同样的情况下,crtp 也存在同样的问题,没什么太大优势可言。归根结底是由于 singleton 模式和 c++ 模板的精神有点背道而驰造成的,和友元或 crtp 的写法关系不大。不过你那种友元的写法确实比较费手。[/quote]
引用 10 楼 u010936098 的回复:
这种说法是对老的编译器是正确的,但符合标准的编译器会处理这个问题。目前多数编译器会在每个调用该模板的cpp文件中为函数生成一份副本,但在链接时会把它们合并,最终代码中只有一个版本。并且,由于静态局部变量的存在,编译器将不会对它进行inline化。 要注意类的静态成员与C的全局静态变量/全局静态函数是完全不一样的,C的全局静态标识符是模块内部连接的,会在每个使用它的模块中生成一个副本,但类的静态成员不是这个语义。事实上,虽然C++中依然支持全局静态变量/函数,但只是为了保持对旧代码的兼容,标准中并不提倡继续使用这一特性,而是建议使用匿名namespace代替它。因些,如果某个编译器把全局静态函数的所有副本合并成了一个,也是很有可能出现的情况。
多谢几位前辈, 尽管没有听懂,只记住了一句话: 模版和单例是违背的。 你们说的关于c++编译器方面的书有没有通俗易懂对教材或资料推荐一下,多谢 [/quote] 咋得出这么个结论呢?都说了另一个帖子里提出的问题不存在。另外其不存在是标准要求的,可以算是有保证了吧。
rocktyt 2013-06-18
  • 打赏
  • 举报
回复
引用 7 楼 combobox2013 的回复:
[quote=引用 6 楼 combobox2013 的回复:] [quote=引用 5 楼 rocktyt2 的回复:] [quote=引用 4 楼 combobox2013 的回复:] [quote=引用 3 楼 ri_aje 的回复:] 楼主只要把相应的概念对普通的类理解透彻,然后再记住类模板实例化以后就变成普通的类,就应该能够推理出它们在类模板情况下的性质了。
引用 2 楼 u010936098 的回复:
在用相同模板参数进行实例化时,如果函数足够简单,并且:在类定义内定义或有inline声明或编译器进行了优化,这时函数就是内联函数,会直接把代码插入到调用处,但取地址的话是同一个地址。如果函数不能内联,那就只有一个。 当用不同模板参数进行实例化时,每个实例生成一个“副本”。 静态成员函数与非静态成员函数都一样,事实上普通成员函数只是比静态成员函数多了一个隐含的参数——this。
参考 第15楼 http://bbs.csdn.net/topics/390485405?page=1#post-394797026 这个帖子,我简答的说一下,是一个单例类, 一个友元模版类, 模版类有getinstance函数, 单例类的构造,拷贝等函数均是私有的。 代码为: 模版类 template <class T> class Singleton { protected: Singleton(){} public: static T& Instance() { static T instance; return instance; } }; 目标单例类 class ExampleSingleton //: public Singleton<ExampleSingleton> { // so that Singleton<ExampleSingleton> can access the // protected constructor friend class Singleton<ExampleSingleton>; //注意友原 protected: ExampleSingleton(){} public: // This class's real functionalities void Write(){printf("Hello, World!");} }; Singleton<ExampleSingleton>::Instance().Write(); 每一个使用Singleton<ExampleSingleton>的地方都可能会生成一个Instance() 因为Singleton<ExampleSingleton>和ExampleSingleton毫无关系; 这带颜色的文字,是一个网友说的, 我问其什么原因,其回答: C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板; 那么静态变量或者静态函数,就会在同一个程序里有又多个版本,因为静态变量或者静态函数是内部连接的,同一程序可以出现多个同名变量或者函数假设这个程序分成N个部分编译,每一份都分别实例化模板的话,就会有N个单例的实例,关键是模板是使用时实例化的,除非预先实例化,并编译好模板,否则,就会出现多份的单例的实例。 所以就会出现这种递归定义的情况,用来解决这个问题。 也就说, 其认为我提供的这种友元写法,是有漏洞的, 如何解决呢? 采用递归定义即可解决。 根本原因是: ]C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板;有多个副本。 所以,我才发这个帖子 [/quote]首先我不知道这说法是否正确 就算是这样,在同一编译单元内还是只有一份的[/quote] 按照你的说法: 同一种类型的实例的函数只有一份的话,那么 [/quote] static T& Instance() { static T instance; return instance; } 中的instance只有一个!!! 是否可以说明: 无论是友元的写法还是 递归定义的写法,都是可行的, 压根就没有漏洞 都可以保证只有一个T !!! [/quote]那个说法所说的漏洞不是你理解的那样…… 就算不是单例或者静态什么的,成员函数始终是只有一份的…… 那个说法是说对于不同的编译单元,因为相互之间是独立的,不知道对方有没有实例化模板所以都会各自实例化导致出现多个T的对象(我不知道这说法的正确性),同一个类的不同对象是共用成员函数的
  • 打赏
  • 举报
回复
给你看一下生成对应的汇编,你就清楚了:

	Test<int> obj1;  
	obj1.Fun();  
0041147E  call        Test<int>::Fun (4111D1h) 
	obj1.Fun2(); 
00411483  lea         ecx,[obj1] 
00411486  call        Test<int>::Fun2 (4111D6h) 

	Test<int>obj2;  
	obj2.Fun();   
0041148B  call        Test<int>::Fun (4111D1h) 
	obj2.Fun2();
00411490  lea         ecx,[obj2] 
00411493  call        Test<int>::Fun2 (4111D6h) 

看到了没有,Test<int>只有只生成一个Fun和一个Fun2代码.
combobox2013 2013-06-18
  • 打赏
  • 举报
回复
引用 6 楼 combobox2013 的回复:
[quote=引用 5 楼 rocktyt2 的回复:] [quote=引用 4 楼 combobox2013 的回复:] [quote=引用 3 楼 ri_aje 的回复:] 楼主只要把相应的概念对普通的类理解透彻,然后再记住类模板实例化以后就变成普通的类,就应该能够推理出它们在类模板情况下的性质了。
引用 2 楼 u010936098 的回复:
在用相同模板参数进行实例化时,如果函数足够简单,并且:在类定义内定义或有inline声明或编译器进行了优化,这时函数就是内联函数,会直接把代码插入到调用处,但取地址的话是同一个地址。如果函数不能内联,那就只有一个。 当用不同模板参数进行实例化时,每个实例生成一个“副本”。 静态成员函数与非静态成员函数都一样,事实上普通成员函数只是比静态成员函数多了一个隐含的参数——this。
参考 第15楼 http://bbs.csdn.net/topics/390485405?page=1#post-394797026 这个帖子,我简答的说一下,是一个单例类, 一个友元模版类, 模版类有getinstance函数, 单例类的构造,拷贝等函数均是私有的。 代码为: 模版类 template <class T> class Singleton { protected: Singleton(){} public: static T& Instance() { static T instance; return instance; } }; 目标单例类 class ExampleSingleton //: public Singleton<ExampleSingleton> { // so that Singleton<ExampleSingleton> can access the // protected constructor friend class Singleton<ExampleSingleton>; //注意友原 protected: ExampleSingleton(){} public: // This class's real functionalities void Write(){printf("Hello, World!");} }; Singleton<ExampleSingleton>::Instance().Write(); 每一个使用Singleton<ExampleSingleton>的地方都可能会生成一个Instance() 因为Singleton<ExampleSingleton>和ExampleSingleton毫无关系; 这带颜色的文字,是一个网友说的, 我问其什么原因,其回答: C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板; 那么静态变量或者静态函数,就会在同一个程序里有又多个版本,因为静态变量或者静态函数是内部连接的,同一程序可以出现多个同名变量或者函数假设这个程序分成N个部分编译,每一份都分别实例化模板的话,就会有N个单例的实例,关键是模板是使用时实例化的,除非预先实例化,并编译好模板,否则,就会出现多份的单例的实例。 所以就会出现这种递归定义的情况,用来解决这个问题。 也就说, 其认为我提供的这种友元写法,是有漏洞的, 如何解决呢? 采用递归定义即可解决。 根本原因是: ]C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板;有多个副本。 所以,我才发这个帖子 [/quote]首先我不知道这说法是否正确 就算是这样,在同一编译单元内还是只有一份的[/quote] 按照你的说法: 同一种类型的实例的函数只有一份的话,那么 [/quote] static T& Instance() { static T instance; return instance; } 中的instance只有一个!!! 是否可以说明: 无论是友元的写法还是 递归定义的写法,都是可行的, 压根就没有漏洞 都可以保证只有一个T !!!
combobox2013 2013-06-18
  • 打赏
  • 举报
回复
引用 5 楼 rocktyt2 的回复:
[quote=引用 4 楼 combobox2013 的回复:] [quote=引用 3 楼 ri_aje 的回复:] 楼主只要把相应的概念对普通的类理解透彻,然后再记住类模板实例化以后就变成普通的类,就应该能够推理出它们在类模板情况下的性质了。
引用 2 楼 u010936098 的回复:
在用相同模板参数进行实例化时,如果函数足够简单,并且:在类定义内定义或有inline声明或编译器进行了优化,这时函数就是内联函数,会直接把代码插入到调用处,但取地址的话是同一个地址。如果函数不能内联,那就只有一个。 当用不同模板参数进行实例化时,每个实例生成一个“副本”。 静态成员函数与非静态成员函数都一样,事实上普通成员函数只是比静态成员函数多了一个隐含的参数——this。
参考 第15楼 http://bbs.csdn.net/topics/390485405?page=1#post-394797026 这个帖子,我简答的说一下,是一个单例类, 一个友元模版类, 模版类有getinstance函数, 单例类的构造,拷贝等函数均是私有的。 代码为: 模版类 template <class T> class Singleton { protected: Singleton(){} public: static T& Instance() { static T instance; return instance; } }; 目标单例类 class ExampleSingleton //: public Singleton<ExampleSingleton> { // so that Singleton<ExampleSingleton> can access the // protected constructor friend class Singleton<ExampleSingleton>; //注意友原 protected: ExampleSingleton(){} public: // This class's real functionalities void Write(){printf("Hello, World!");} }; Singleton<ExampleSingleton>::Instance().Write(); 每一个使用Singleton<ExampleSingleton>的地方都可能会生成一个Instance() 因为Singleton<ExampleSingleton>和ExampleSingleton毫无关系; 这带颜色的文字,是一个网友说的, 我问其什么原因,其回答: C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板; 那么静态变量或者静态函数,就会在同一个程序里有又多个版本,因为静态变量或者静态函数是内部连接的,同一程序可以出现多个同名变量或者函数假设这个程序分成N个部分编译,每一份都分别实例化模板的话,就会有N个单例的实例,关键是模板是使用时实例化的,除非预先实例化,并编译好模板,否则,就会出现多份的单例的实例。 所以就会出现这种递归定义的情况,用来解决这个问题。 也就说, 其认为我提供的这种友元写法,是有漏洞的, 如何解决呢? 采用递归定义即可解决。 根本原因是: ]C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板;有多个副本。 所以,我才发这个帖子 [/quote]首先我不知道这说法是否正确 就算是这样,在同一编译单元内还是只有一份的[/quote] 按照你的说法: 同一种类型的实例的函数只有一份的话,那么
rocktyt 2013-06-18
  • 打赏
  • 举报
回复
引用 4 楼 combobox2013 的回复:
[quote=引用 3 楼 ri_aje 的回复:] 楼主只要把相应的概念对普通的类理解透彻,然后再记住类模板实例化以后就变成普通的类,就应该能够推理出它们在类模板情况下的性质了。
引用 2 楼 u010936098 的回复:
在用相同模板参数进行实例化时,如果函数足够简单,并且:在类定义内定义或有inline声明或编译器进行了优化,这时函数就是内联函数,会直接把代码插入到调用处,但取地址的话是同一个地址。如果函数不能内联,那就只有一个。 当用不同模板参数进行实例化时,每个实例生成一个“副本”。 静态成员函数与非静态成员函数都一样,事实上普通成员函数只是比静态成员函数多了一个隐含的参数——this。
参考 第15楼 http://bbs.csdn.net/topics/390485405?page=1#post-394797026 这个帖子,我简答的说一下,是一个单例类, 一个友元模版类, 模版类有getinstance函数, 单例类的构造,拷贝等函数均是私有的。 代码为: 模版类 template <class T> class Singleton { protected: Singleton(){} public: static T& Instance() { static T instance; return instance; } }; 目标单例类 class ExampleSingleton //: public Singleton<ExampleSingleton> { // so that Singleton<ExampleSingleton> can access the // protected constructor friend class Singleton<ExampleSingleton>; //注意友原 protected: ExampleSingleton(){} public: // This class's real functionalities void Write(){printf("Hello, World!");} }; Singleton<ExampleSingleton>::Instance().Write(); 每一个使用Singleton<ExampleSingleton>的地方都可能会生成一个Instance() 因为Singleton<ExampleSingleton>和ExampleSingleton毫无关系; 这带颜色的文字,是一个网友说的, 我问其什么原因,其回答: C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板; 那么静态变量或者静态函数,就会在同一个程序里有又多个版本,因为静态变量或者静态函数是内部连接的,同一程序可以出现多个同名变量或者函数假设这个程序分成N个部分编译,每一份都分别实例化模板的话,就会有N个单例的实例,关键是模板是使用时实例化的,除非预先实例化,并编译好模板,否则,就会出现多份的单例的实例。 所以就会出现这种递归定义的情况,用来解决这个问题。 也就说, 其认为我提供的这种友元写法,是有漏洞的, 如何解决呢? 采用递归定义即可解决。 根本原因是: ]C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板;有多个副本。 所以,我才发这个帖子 [/quote]首先我不知道这说法是否正确 就算是这样,在同一编译单元内还是只有一份的
combobox2013 2013-06-18
  • 打赏
  • 举报
回复
引用 3 楼 ri_aje 的回复:
楼主只要把相应的概念对普通的类理解透彻,然后再记住类模板实例化以后就变成普通的类,就应该能够推理出它们在类模板情况下的性质了。
引用 2 楼 u010936098 的回复:
在用相同模板参数进行实例化时,如果函数足够简单,并且:在类定义内定义或有inline声明或编译器进行了优化,这时函数就是内联函数,会直接把代码插入到调用处,但取地址的话是同一个地址。如果函数不能内联,那就只有一个。 当用不同模板参数进行实例化时,每个实例生成一个“副本”。 静态成员函数与非静态成员函数都一样,事实上普通成员函数只是比静态成员函数多了一个隐含的参数——this。
参考 第15楼 http://bbs.csdn.net/topics/390485405?page=1#post-394797026 这个帖子,我简答的说一下,是一个单例类, 一个友元模版类, 模版类有getinstance函数, 单例类的构造,拷贝等函数均是私有的。 代码为: 模版类 template <class T> class Singleton { protected: Singleton(){} public: static T& Instance() { static T instance; return instance; } }; 目标单例类 class ExampleSingleton //: public Singleton<ExampleSingleton> { // so that Singleton<ExampleSingleton> can access the // protected constructor friend class Singleton<ExampleSingleton>; //注意友原 protected: ExampleSingleton(){} public: // This class's real functionalities void Write(){printf("Hello, World!");} }; Singleton<ExampleSingleton>::Instance().Write(); 每一个使用Singleton<ExampleSingleton>的地方都可能会生成一个Instance() 因为Singleton<ExampleSingleton>和ExampleSingleton毫无关系; 这带颜色的文字,是一个网友说的, 我问其什么原因,其回答: C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板; 那么静态变量或者静态函数,就会在同一个程序里有又多个版本,因为静态变量或者静态函数是内部连接的,同一程序可以出现多个同名变量或者函数假设这个程序分成N个部分编译,每一份都分别实例化模板的话,就会有N个单例的实例,关键是模板是使用时实例化的,除非预先实例化,并编译好模板,否则,就会出现多份的单例的实例。 所以就会出现这种递归定义的情况,用来解决这个问题。 也就说, 其认为我提供的这种友元写法,是有漏洞的, 如何解决呢? 采用递归定义即可解决。 根本原因是: ]C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板;有多个副本。 所以,我才发这个帖子
橡木疙瘩 2013-06-18
  • 打赏
  • 举报
回复
引用 12 楼 combobox2013 的回复:
多谢几位前辈, 尽管没有听懂,只记住了一句话: 模版和单例是违背的。 你们说的关于c++编译器方面的书有没有通俗易懂对教材或资料推荐一下,多谢
你还是没明白。lm_whales所说的那种情况只会在一些很老的编译器中出现(或许VC6和BCB5是这样?记不清了。),现在的编译器基本上不会出现这种问题,所以完全不必担心用模板实现的单实例会出问题。 在现在的编译器中,Singleton<ExampleSingleton>::Instance最终只有一份,Singleton<ExampleSingleton2>则是另一份,既不会冲突也不会有重复。模板与singleton并不违背。
combobox2013 2013-06-18
  • 打赏
  • 举报
回复
引用 11 楼 ri_aje 的回复:
[quote=引用 4 楼 combobox2013 的回复:] [quote=引用 3 楼 ri_aje 的回复:] 楼主只要把相应的概念对普通的类理解透彻,然后再记住类模板实例化以后就变成普通的类,就应该能够推理出它们在类模板情况下的性质了。
引用 2 楼 u010936098 的回复:
在用相同模板参数进行实例化时,如果函数足够简单,并且:在类定义内定义或有inline声明或编译器进行了优化,这时函数就是内联函数,会直接把代码插入到调用处,但取地址的话是同一个地址。如果函数不能内联,那就只有一个。 当用不同模板参数进行实例化时,每个实例生成一个“副本”。 静态成员函数与非静态成员函数都一样,事实上普通成员函数只是比静态成员函数多了一个隐含的参数——this。
参考 第15楼 http://bbs.csdn.net/topics/390485405?page=1#post-394797026 这个帖子,我简答的说一下,是一个单例类, 一个友元模版类, 模版类有getinstance函数, 单例类的构造,拷贝等函数均是私有的。 代码为: 模版类 template <class T> class Singleton { protected: Singleton(){} public: static T& Instance() { static T instance; return instance; } }; 目标单例类 class ExampleSingleton //: public Singleton<ExampleSingleton> { // so that Singleton<ExampleSingleton> can access the // protected constructor friend class Singleton<ExampleSingleton>; //注意友原 protected: ExampleSingleton(){} public: // This class's real functionalities void Write(){printf("Hello, World!");} }; Singleton<ExampleSingleton>::Instance().Write(); 每一个使用Singleton<ExampleSingleton>的地方都可能会生成一个Instance() 因为Singleton<ExampleSingleton>和ExampleSingleton毫无关系; 这带颜色的文字,是一个网友说的, 我问其什么原因,其回答: C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板; 那么静态变量或者静态函数,就会在同一个程序里有又多个版本,因为静态变量或者静态函数是内部连接的,同一程序可以出现多个同名变量或者函数假设这个程序分成N个部分编译,每一份都分别实例化模板的话,就会有N个单例的实例,关键是模板是使用时实例化的,除非预先实例化,并编译好模板,否则,就会出现多份的单例的实例。 所以就会出现这种递归定义的情况,用来解决这个问题。 也就说, 其认为我提供的这种友元写法,是有漏洞的, 如何解决呢? 采用递归定义即可解决。 根本原因是: ]C++的静态变量或者静态函数,和模板一起,就会让单例模式失去作用,因为可以在每个实现的地方实例化模板;有多个副本。 所以,我才发这个帖子 [/quote] 我觉得他说的问题不存在,在某些非常 tricky 的情况下,可能存在问题,但是同样的情况下,crtp 也存在同样的问题,没什么太大优势可言。归根结底是由于 singleton 模式和 c++ 模板的精神有点背道而驰造成的,和友元或 crtp 的写法关系不大。不过你那种友元的写法确实比较费手。[/quote]
引用 10 楼 u010936098 的回复:
这种说法是对老的编译器是正确的,但符合标准的编译器会处理这个问题。目前多数编译器会在每个调用该模板的cpp文件中为函数生成一份副本,但在链接时会把它们合并,最终代码中只有一个版本。并且,由于静态局部变量的存在,编译器将不会对它进行inline化。 要注意类的静态成员与C的全局静态变量/全局静态函数是完全不一样的,C的全局静态标识符是模块内部连接的,会在每个使用它的模块中生成一个副本,但类的静态成员不是这个语义。事实上,虽然C++中依然支持全局静态变量/函数,但只是为了保持对旧代码的兼容,标准中并不提倡继续使用这一特性,而是建议使用匿名namespace代替它。因些,如果某个编译器把全局静态函数的所有副本合并成了一个,也是很有可能出现的情况。
多谢几位前辈, 尽管没有听懂,只记住了一句话: 模版和单例是违背的。 你们说的关于c++编译器方面的书有没有通俗易懂对教材或资料推荐一下,多谢
ri_aje 2013-06-18
  • 打赏
  • 举报
回复
楼主只要把相应的概念对普通的类理解透彻,然后再记住类模板实例化以后就变成普通的类,就应该能够推理出它们在类模板情况下的性质了。
橡木疙瘩 2013-06-17
  • 打赏
  • 举报
回复
在用相同模板参数进行实例化时,如果函数足够简单,并且:在类定义内定义或有inline声明或编译器进行了优化,这时函数就是内联函数,会直接把代码插入到调用处,但取地址的话是同一个地址。如果函数不能内联,那就只有一个。 当用不同模板参数进行实例化时,每个实例生成一个“副本”。 静态成员函数与非静态成员函数都一样,事实上普通成员函数只是比静态成员函数多了一个隐含的参数——this。
combobox2013 2013-06-17
  • 打赏
  • 举报
回复

64,636

社区成员

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

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