首页 > 代码库 > 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;}

图像 4

 

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;}

图像 5

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 编写单例模式。