首页 > 代码库 > 0715-----C++Primer听课笔记-----------函数指针 、单例模式
0715-----C++Primer听课笔记-----------函数指针 、单例模式
1.函数指针
1.1 普通成员函数指针包含类名信息以及const属性,指向具体函数是必须加上&符号。
#include <iostream>using namespace std;class Test{ public: void setValue(const string &s, int a){ s_ = s; a_ = a; } void print() const{ cout << s_ << endl << a_ << endl; } private: string s_; int a_;};int main(int argc, const char *argv[]){ void (Test::*pfunc)(const string&, int) = &Test::setValue; void (Test::*pfunc1)()const = &Test::print; Test t; (t.*pfunc)("hello", 3); (t.*pfunc1)(); Test *t1 = new Test; (t1->*pfunc)("hello", 3); (t1->*pfunc1)(); delete t1; return 0;}
1.2 static 函数指针不包含类名, & 符号也不是必须。
#include <iostream>using namespace std;class Test{ public: static void print(){ cout << "hello world " << endl; }};int main(int argc, const char *argv[]){ void(*funcPtr)() = &Test::print; funcPtr(); return 0;}
2.单例模式
2.1 将构造函数设为私有, 通过调用static 成员函数生成对象。此时通过多次调用static函数可以生成不同的对象。
#include <iostream>#include <string>#include <vector>using namespace std;/* *对象不唯一 */class Singleton{ public: static Singleton *getInstance(){ Singleton *ps = new Singleton; return ps; } private: Singleton(){}};int main(int argc, const char *argv[]){ Singleton *ps = Singleton::getInstance(); cout << ps << endl; Singleton *ps2 = Singleton::getInstance(); cout << ps2 << endl; return 0;}
2.2 为解决上述对象不唯一问题, 设置一静态变量,通过判断是否为空,去生成对象,看似保证了唯一性。
#include <iostream>#include <string>#include <vector>using namespace std;/* *多线程环境下存在竞态问题 */class Singleton{ public: static Singleton *getInstance(){ if(pInstance_ == NULL){ pInstance_ = new Singleton; } return pInstance_; } private: Singleton(){} static Singleton *pInstance_;};Singleton *Singleton::pInstance_ = NULL;int main(int argc, const char *argv[]){ Singleton *ps = Singleton::getInstance(); cout << ps << endl; Singleton *ps2 = Singleton::getInstance(); cout << ps2 << endl; return 0;}
2.3 但是上述代码在多线程环境下存在竞态问题(if 语句处,多个线程同时进入时,可以生成不同的对象)。 如下所示。
#include <iostream>#include <string>#include <vector>using namespace std;/* *多线程环境下存在竞态问题 */class Singleton{ public: static Singleton *getInstance(){ if(pInstance_ == NULL){ sleep(2); pInstance_ = new Singleton; } return pInstance_; } private: Singleton(){} static Singleton *pInstance_;};Singleton *Singleton::pInstance_ = NULL;void* threadFunc(void *arg){ Singleton *ps = Singleton::getInstance(); cout << ps << endl;}int main(int argc, const char *argv[]){ vector<pthread_t> vec(10); for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_create(&*it, NULL, threadFunc, NULL); } for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_join(*it, NULL); } return 0;}
2.4 为解决上述多线程竞态问题,我们每次检查指针前都上锁。这样就保证了对象在多线程环境下也是唯一的,如下所示。
#include <iostream>#include <vector>#include "mutexlock.h"using namespace std;/* *为了解决竞态问题 加锁 */class Singleton{ public: static Singleton *getInstance(){ mutex_.lock(); if(pInstance_ == NULL){ sleep(2); pInstance_ = new Singleton; } mutex_.unlock(); return pInstance_; } private: Singleton(){} static Singleton *pInstance_; static Mutexlock mutex_;};/* *static 成员变量在类的内部是声明 必须在类的外部定义 */Singleton *Singleton::pInstance_ = NULL;Mutexlock Singleton::mutex_;void* threadFunc(void *arg){ Singleton *ps = Singleton::getInstance(); cout << ps << endl;}int main(int argc, const char *argv[]){ vector<pthread_t> vec(10); for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_create(&*it, NULL, threadFunc, NULL); } for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_join(*it, NULL); } return 0;}
2.4 上述程序每次获取对象都要加锁,造成了锁争用,使得效率降低,因此引用双重锁模式。
#include <iostream>#include <vector>#include "mutexlock.h"using namespace std;/* *每次调用都要征用锁 这是的效率降低 * 因此 采用双重锁 */class Singleton{ public: static Singleton *getInstance(){ if(pInstance_ == NULL){ mutex_.lock(); if(pInstance_ == NULL){ sleep(2); pInstance_ = new Singleton; } mutex_.unlock(); } return pInstance_; } private: Singleton(){} static Singleton *pInstance_; static Mutexlock mutex_;};/* *static 成员变量在类的内部是声明 必须在类的外部定义 */Singleton *Singleton::pInstance_ = NULL;Mutexlock Singleton::mutex_;void* threadFunc(void *arg){ Singleton *ps = Singleton::getInstance(); cout << ps << endl;}int main(int argc, const char *argv[]){ vector<pthread_t> vec(10); for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_create(&*it, NULL, threadFunc, NULL); } for(vector<pthread_t>::iterator it = vec.begin(); it != vec.end(); ++it){ pthread_join(*it, NULL); } return 0;}
2.5 总结思路
单例模式的编写:
a) 构造函数设为私有,此时无法生成对象
b) 编写一个成员函数来生成对象,但是无法调用。
c) 将该函数设为static,此时可以生成对象,但是对象不唯一。
d) 添加一个static指针成员,仅当该指针为NULL(也就是第一次访问时)才去生成对象。
e) 但是此时的代码在多线程环境下存在竞态问题。
f) 于是我们每次检查指针前都要进行加锁。
g) 此时每次获取对象都要加锁,锁争用过多,影响效率,于是我们引入“双重锁”模式(Double Check Lock Pattern, DCLP)。这种模式采用了两重判断,其中内部的判断采用了锁,保证结果的正确性,外面的检查保证大部分线程不会进入争用锁。
h) 后面我们采用pthread_once 编写单例模式。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。