ios判断程序是否处于调试状态

5948次浏览

当一个应用被调试的时候,会给进程设置一个标识(P_TRACED),我们可以通过检测该进程是否有设置这个标识来检测进程是否正在被调试以保护好我们的应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <sys/types.h>
#include <sys/sysctl.h>
 
static int check_debugger( ) __attribute__((always_inline));
 
static int check_debugger( )
{
    size_t size = sizeof(struct kinfo_proc);
    struct kinfo_proc info;
    int ret,name[4];
 
    memset(&info, 0, sizeof(struct kinfo_proc));
 
    name[0] = CTL_KERN;
    name[1] = KERN_PROC;
    name[2] = KERN_PROC_PID;
    name[3] = getpid();
 
    if((ret = (sysctl(name, 4, &info, &size, NULL, 0)))){
        return ret;  //sysctl() failed for some reason
    }
 
    return (info.kp_proc.p_flag & P_TRACED) ? 1 : 0;
}

如果你不确信产生的目标代码以inline的方式编译该函数,你也可以将其转化成宏的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#define DEBUGGER_CHECK {                                \
    size_t size = sizeof(struct kinfo_proc);            \
    struct kinfo_proc info;                             \
    int ret,name[4];                                    \
                                                        \
    memset(&info, 0, sizeof(struct kinfo_proc));        \
                                                        \
    name[0] = CTL_KERN;                                 \
    name[1] = KERN_PROC;                                \
    name[2] = KERN_PROC_PID;                            \
    name[3] = getpid();                                 \
                                                        \
    if(ret = (sysctl(name, 4, &info, &size, NULL, 0))){ \
        return (EXIT_FAILURE);                          \
    }                                                   \
                                                        \
    if(info.kp_proc.p_flag & P_TRACED){                 \
        /* Code to react to debugging goes here */      \
    }                                                   \
}

C++的STL是如何实现算法和数据结构分离的

454次浏览

STL看起来是使用了面向对象,但实际上是大部分都是面向过程了。
STL的很多算法,就拿sort函数来说吧。

1
void sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp);

只要数据结构的跌代器是随机访问的就可以使用。比如vector, list,同时也兼容普通数组int[]。

这里说到跌代器,STL有一整套跌代器的实现标准:
1、实现begin和end函数,是要全局的
如vecotr:

1
vecotr<T>::Iterator begin(vecotr<T>);

而不是 vecotr的成员函数begin,这点要区分。
2、跌代器实现前至++运算
3、跌代器实现 * 运算
4、跌代器实现 != 运算

基本这四点就可以完成了,可以根据这个规则自己实现一个跌代器。

有了跌代器后,那么对于算法来说他们基本就一样了,开头,结尾,自增,以次访问就可以了。

所以一个sort就可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
vecotr<int> a;
string b;
list<float> c;
 
sort(a.begin(), a.end());
sort(b.begin(),b.end());
sort(c.begin(),c.end());
 
static bool less(int a1, int a2)
{
    return a1 < a2;
}
 
sort(a.begin(), a.begin()+5, less); // 对前5个排序
sort(a.begin(), a.end(), less);
sort(a.begin(), a.end(), [](int a1, int a2) {
    return a1 <= a2; // 匿名函数
});

结论就是算法跟数据结构是通过跌代器进行沟通的,所以学好跌代器,STL才算学好,要会用,也要懂为原理。

最新ios设备标签与设备型号的对应关系

1161次浏览

1.这种是在较高层次获取设备类型,返回的是 iPhone , iPod , iPad 。适合要求不高的。

1
NSString *deviceType = [[UIDevice currentDevice] model];

2.这是Linux中获取设备类型的方法,主要是C语言的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <sys/types.h>
#include <sys/sysctl.h>
 
- (NSString *)getDeviceVersionInfo
{
    size_t size;
    // get the length of machine name
    sysctlbyname("hw.machine", NULL, &size, NULL, 0);
    // get machine name
    char *machine = malloc(size);
    sysctlbyname("hw.machine", machine, &size, NULL, 0);
    NSString *platform = [NSString stringWithFormat:@"%s", machine];
    free(machine);
 
    return platform;
}
1
2
3
4
5
6
7
8
9
10
#include <sys/utsname.h>
 
- (NSString *)getDeviceVersionInfo
{
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *platform = [NSString stringWithFormat:@"%s", systemInfo.machine];
 
    return platform;
}

  
通过,如上方式即可获取到设备的型号信息,具体对应关系如下,

iPhone

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
	iPhone8,1		iPhone6s
	iPhone8,2		iPhone6s-plus
	iPhone8,4		iPhone5se
	iPhone7,1		iPhone6-plus
	iPhone7,2		iPhone6
	iPhone6,1		iPhone5s
	iPhone6,2		iPhone5s
	iPhone5,1		iPhone5(移动,联通)
	iPhone5,2		iPhone5(移动,电信,联通)
	iPhone5,3		iPhone5c
	iPhone5,4		iPhone5c
	iPhone4,1		iPhone4S
	iPhone3,1		iPhone4(移动,联通)
	iPhone3,2		iPhone4(联通)
	iPhone3,3		iPhone4(电信)
	iPhone2,1		iPhone3GS
	iPhone1,2		iPhone3G
	iPhone1,1		iPhone

iPad

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
	iPad1,1			iPad1
	iPad2,1			iPad2(Wifi)
	iPad2,2			iPad2(GSM)
	iPad2,3			iPad2(CDMA)
	iPad2,4			iPad2(32nm)
	iPad2,5			iPadmini(Wifi)
	iPad2,6			iPadmini(GSM)
	iPad2,7			iPadmini(CDMA)
	iPad3,1			iPad3(Wifi)
	iPad3,2			iPad3(CDMA)
	iPad3,3			iPad3(4G)
	iPad3,4			iPad4(Wifi)
	iPad3,5			iPad4(4G)
	iPad3,6			iPad4(CDMA)
	iPad4,1			iPadAir
	iPad4,2			iPadAir
	iPad4,3			iPadAir
	iPad4,4			iPadmini2
	iPad4,5			iPadmini2
	iPad4,6			iPadmini2
	iPad4,7			iPadmini3
	iPad4,8			iPadmini3
	iPad4,9			iPadmini3
	iPad5,1			iPadmini4
	iPad5,2			iPadmini4
	iPad5,3			iPadAir2
	iPad5,4			iPadAir2
	iPad6,3			iPadPro(9.7inch)
	iPad6,4			iPadPro(9.7inch)
	iPad6,7			iPadPro(12.9inch)
	iPad6,8			iPadPro(12.9inch)

iPod、AppleTV、AppleWatch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	iPod6,1			iPodtouch6
	iPod5,1			iPodtouch5
	iPod4,1			iPodtouch4
	iPod3,1			iPodtouch3
	iPod2,1			iPodtouch2
	iPod1,1			iPodtouch
 
	AppleTV2,1		AppleTV2
	AppleTV3,1		AppleTV3
	AppleTV3,2		AppleTV3
	AppleTV5,3		AppleTV4
 
	Watch1,1		AppleWatch
	Watch1,2		AppleWatch

使用参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
- (NSString*) getDeviceName
{
    NSString *deviceString = [self getDeviceVersionInfo]
 
    NSArray *modelArray = @[
 
                            @"i386", @"x86_64",
 
                            @"iPhone1,1",
                            @"iPhone1,2",
                            @"iPhone2,1",
                            @"iPhone3,1",
                            @"iPhone3,2",
                            @"iPhone3,3",
                            @"iPhone4,1",
                            @"iPhone5,1",
                            @"iPhone5,2",
                            @"iPhone5,3",
                            @"iPhone5,4",
                            @"iPhone6,1",
                            @"iPhone6,2",
 
                            @"iPod1,1",
                            @"iPod2,1",
                            @"iPod3,1",
                            @"iPod4,1",
                            @"iPod5,1",
 
                            @"iPad1,1",
                            @"iPad2,1",
                            @"iPad2,2",
                            @"iPad2,3",
                            @"iPad2,4",
                            @"iPad3,1",
                            @"iPad3,2",
                            @"iPad3,3",
                            @"iPad3,4",
                            @"iPad3,5",
                            @"iPad3,6",
 
                            @"iPad2,5",
                            @"iPad2,6",
                            @"iPad2,7",
                            ];
    NSArray *modelNameArray = @[
 
                                @"iPhone Simulator", @"iPhone Simulator",
 
                                @"iPhone 2G",
                                @"iPhone 3G",
                                @"iPhone 3GS",
                                @"iPhone 4(GSM)",
                                @"iPhone 4(GSM Rev A)",
                                @"iPhone 4(CDMA)",
                                @"iPhone 4S",
                                @"iPhone 5(GSM)",
                                @"iPhone 5(GSM+CDMA)",
                                @"iPhone 5c(GSM)",
                                @"iPhone 5c(Global)",
                                @"iphone 5s(GSM)",
                                @"iphone 5s(Global)",
 
                                @"iPod Touch 1G",
                                @"iPod Touch 2G",
                                @"iPod Touch 3G",
                                @"iPod Touch 4G",
                                @"iPod Touch 5G",
 
                                @"iPad",
                                @"iPad 2(WiFi)",
                                @"iPad 2(GSM)",
                                @"iPad 2(CDMA)",
                                @"iPad 2(WiFi + New Chip)",
                                @"iPad 3(WiFi)",
                                @"iPad 3(GSM+CDMA)",
                                @"iPad 3(GSM)",
                                @"iPad 4(WiFi)",
                                @"iPad 4(GSM)",
                                @"iPad 4(GSM+CDMA)",
 
                                @"iPad mini (WiFi)",
                                @"iPad mini (GSM)",
                                @"ipad mini (GSM+CDMA)"
                                ];
    NSInteger modelIndex = - 1;
    NSString *modelNameString = nil;
    modelIndex = [modelArray indexOfObject:deviceString];
    if (modelIndex >= 0 && modelIndex < [modelNameArray count]) {
        modelNameString = [modelNameArray objectAtIndex:modelIndex];
    }
 
    NSLog(@"----设备类型---%@",modelNameString);
    return modelNameString;
}

c++字节压缩ByteData

1366次浏览

不管什么语言,一个变量至少要占1个字节(Byte),像char,bool,byte类型都是占1个字节,无符号的范围是0~255,有符号是-128~127。

在特殊情况下,当明确知道取值范围小于0~255,如0~3。这时候就会考虑怎么能再压缩内存。因为实际用不到1个字节,只用2个位(bit)即可,但只占2位的的类型是没有的。也许你会问,这省了这么点内存有什么用,即使使用int也没有什么大不了的。

对的,当只有一个两个的时候是不需要考虑,不过当面临大数组,成百上千,甚至上万个的时候,2个位跟1个字节相差了4倍,可以节省3/4的内存,压缩75%还是很可观的。

还有一种情况是数据库对二进制数据存储是有长度限制的,做服务器的话都知道用户数据上会有大量的0~1标记,这时候使用字节压缩1个用户就会节省87.5%的储存或内存。1w个,10w个用户那节省的可不是一点点了。

好了,不多说了,核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 读取函数
// @param data 存放二进制数据
// @param eachBit 每eachBit个bit位代表一个值
// @param index 获取指定索引位置的值
int get(const vector<unsigned char>& data, int eachBit, int index)
{
    int length = (int)data.size();
    int i = (index * eachBit) / 8;
    int  m = (index * eachBit) % 8;
    unsigned int mask = (0x01 << eachBit) - 0x01;
 
    if (i < 0 || i >= length || m < 0) {
        return 0;
    }
 
    return (data[i] & (mask << m)) >> m;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 设置函数
// @param data 存放二进制数据
// @param eachBit 每eachBit个bit位代表一个值
// @param index 指定要修改的索引位置
// @param value 新的值
void set(vector<unsigned char>& data, int eachBit, int index, int value)
{
    int length = (int)data.size();
    int i = (index * eachBit) / 8;
    int  m = (index * eachBit) % 8;
    unsigned int mask = (0x01 << eachBit) - 0x01;
 
    if (i < 0 || i >= length || m < 0) {
        return ;
    }
 
    mask = mask << m;
    value = value << m;
 
    // assert(value == (value & mask));
 
    data[i] = (data[i] & ~mask) | (value & mask);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 样例
#include<stdio.h>
#include<vector>
using namespace std;
 
int main()
{
    vector<unsigned char> data = {34, 2, 57, 123, 65, 93, 33};
 
    int a = get(data, 2, 8);
    set(data, 2, 8, a+1);
    int b = get(data, 2, 8);
 
    printf("a=%d b=%d \n", a, b);
}
1
2
// 打印结果
a=1 b=2

上面为通用算法代码,下面的是用c++对代码进行了包装,增加[]访问及迭代器的操作
点击下载:ByteData.zip

如何提高 C/C++ 编程能力

288次浏览

一万小时定律:作家格拉德威尔在《异类》一书中指出:人们眼中的天才之所以卓越非凡,并非天资超人一等,而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成超凡的必要条件。
他将此称为“一万小时定律”。要成为某个领域的专家,需要10000小时,按比例计算就是:如果每天工作八个小时,一周工作五天,那么成为一个领域的专家至少需要五年

c/c++尤其适合这句话,如果下定决心要学c/c++,那么就不要有速成的思想

1、多敲代码,多思考
2、多敲代码,多思考
3、多敲代码,多思考

以上3点就是提高c/c++编程能力最捷径的方法了!!

编程提升技巧:

1、重写算法,选一个算法(如排序),查看并敲写所有现有的算法。然后思考有没有更好的办法,或者换一个写法会怎么,能不能再优化一些,也可以基于其中的某一个算法思考。
2、编写大型项目,大型项目跟小项目完全是两码事,会遇到各种各样的问题,在解决问题中会锻炼代码编写的能力,及思维能力。
3、参与不同类型的项目开发,不同项目会有不同项目的需求及问题,可以拓展眼界范围。
4、学习开发模式
5、学习其它编程语言(如java,c#,lua,js,php等),了解其中的优缺点。
6、总之,多敲代码,多思考

蓝溪阁,一段历史 ——《遗迹之塔》

509次浏览

【蓝溪阁,一段历史 (一)】

【蓝溪阁,一段历史 (二)】

【蓝溪阁,一段历史 (三)】

【蓝溪阁,一段历史 (四)】

【蓝溪阁,一段历史 (五)】

【蓝溪阁,一段历史 (六)】

【蓝溪阁,一段历史 (七)】

【蓝溪阁,一段历史 (八)】

 

64af63cd83ee47e2b07aacf096b7de54

c++ Singleton 单例

1645次浏览

单例模式也称为单件模式、单子模式,可能是使用最广泛的设计模式。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。有很多地方需要这样的功能模块,如系统的日志输出,GUI应用必须是单鼠标,MODEM的联接需要一条且只需要一条电话线,操作系统只能有一个窗口管理器,一台PC连一个键盘。

单例模式有许多种实现方法,在C++中,甚至可以直接用一个全局变量做到这一点,但这样的代码显的很不优雅。 使用全局对象能够保证方便地访问实例,但是不能保证只声明一个对象——也就是说除了一个全局实例外,仍然能创建相同类的本地实例。

《设计模式》一书中给出了一种很不错的实现,定义一个单例类,使用类的私有静态指针变量指向类的唯一实例,并用一个公有的静态方法获取该实例。
单例模式通过类本身来管理其唯一实例,这种特性提供了解决问题的方法。唯一的实例是类的一个普通对象,但设计这个类时,让它只能创建一个实例并提供对此实例的全局访问。唯一实例类Singleton在静态成员函数中隐藏创建实例的操作。习惯上把这个成员函数叫做Instance(),它的返回值是唯一实例的指针。
定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class CSingleton
{
private:
	CSingleton()   //构造函数是私有的
	{
	}
	CSingleton(const CSingleton &);  
	CSingleton & operator = (const CSingleton &); 
 
	static CSingleton *m_pInstance;
public:
	static CSingleton * getInstance()
	{
		if(m_pInstance == NULL)  //判断是否第一次调用
			m_pInstance = new CSingleton();
		return m_pInstance;
	}
};

用户访问唯一实例的方法只有getInstance()成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的。getInstance()使用懒惰初始化,也就是说它的返回值是当这个函数首次被访问时被创建的。这是一种防弹设计——所有getInstance()之后的调用都返回相同实例的指针:
CSingleton* p1 = CSingleton :: getInstance();
CSingleton* p2 = p1-> getInstance();
CSingleton & ref = * CSingleton :: getInstance();

关于Singleton(const Singleton);和 Singleton & operate = (const Singleton&);函数,需要声明成私有的,并且只声明不实现。这样,如果如果通过 CSingleton copy = *CSingleton::getInstance()等方式来使用单例时,不管是在友元类中还是其他的,编译器都是报错。如果在c++11中,可以Singleton(const Singleton) = delete;来明确函数是删除的。

单例类CSingleton有以下特征:
它有一个指向唯一实例的静态指针m_pInstance,并且是私有的;
它有一个公有的函数,可以获取这个唯一的实例,并且在需要的时候创建该实例;
它的构造函数是私有的,这样就不能从别处创建该类的实例。

大多数时候,这样的实现都不会出现问题。有经验的读者可能会问,m_pInstance指向的空间什么时候释放呢?更严重的问题是,该实例的析构函数什么时候执行?

如果在类的析构行为中有必须的操作,比如关闭文件,释放外部资源,那么上面的代码无法实现这个要求。我们需要一种方法,正常的删除该实例。
可以在程序结束时调用getInstance(),并对返回的指针掉用delete操作。这样做可以实现功能,但不仅很丑陋,而且容易出错。因为这样的附加代码很容易被忘记,而且也很难保证在delete之后,没有代码再调用getInstance函数。

一个妥善的方法是让这个类自己知道在合适的时候把自己删除,或者说把删除自己的操作挂在操作系统中的某个合适的点上,使其在恰当的时候被自动执行。
我们知道,程序在结束的时候,系统会自动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量,就像这些静态成员也是全局变量一样。利用这个特征,我们可以在单例类中定义一个这样的静态成员变量,而它的唯一工作就是在析构函数中删除单例类的实例。如下面的代码中的CGarbo类(Garbo意为垃圾工人):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class CSingleton
{
private:
	CSingleton()
	{
	}
	CSingleton(const CSingleton &) = delete;  
	CSingleton & operator = (const CSingleton &) = delete; 
 
	static CSingleton *m_pInstance;
	class CGarbo   //它的唯一工作就是在析构函数中删除CSingleton的实例
	{
	public:
		~CGarbo()
		{
			if(CSingleton::m_pInstance)
				delete CSingleton::m_pInstance;
		}
	};
	static CGarbo Garbo;  //定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数
public:
	static CSingleton * getInstance()
	{
		if(m_pInstance == NULL)  //判断是否第一次调用
			m_pInstance = new CSingleton();
		return m_pInstance;
	}
};

类CGarbo被定义为CSingleton的私有内嵌类,以防该类被在其他地方滥用。
程序运行结束时,系统会调用CSingleton的静态成员Garbo的析构函数,该析构函数会删除单例的唯一实例。
使用这种方法释放单例对象有以下特征:
在单例类内部定义专有的嵌套类;
在单例类内定义私有的专门用于释放的静态成员;
利用程序在结束时析构全局变量的特性,选择最终的释放时机;
使用单例的代码不需要任何操作,不必关心对象的释放。

进一步的讨论
但是添加一个类的静态对象,总是让人不太满意,所以有人用如下方法来重新实现单例和解决它相应的问题,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
class CSingleton
{
private:
	CSingleton()   //构造函数是私有的
	{
	}
	CSingleton(const CSingleton &) = delete;  
	CSingleton & operator = (const CSingleton &) = delete;  
public:
	static CSingleton * getInstance()
	{
		static CSingleton instance;   //局部静态变量
		return &instance;
	}
};

一般来说一个程序里会有大量的单例,如果每个都这么写肯定是很累的,那么就考虑实现一个单例模板。一般来说呢,会有好几个版本的模板实现。这里就不一一说明了,只提供我自己觉得算是比较好的一种方式,同时也包括了原子操作及非原子操作。该代码使用了c++11特性。
如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
 
class $atomic {};        // 原子,线程安全
class $nonatomic {};     // 非原子,非线程安全
 
template <class T, class Atomicable = $nonatomic> 
class Singleton
{
 
protected:
    Singleton() {}
    virtual ~Singleton() {}
 
public:
    static inline T* getInstance();
 
private:
    static T* __getInstance(const $nonatomic&);
    static T* __getInstance(const $atomic&);
};
 
template inline T* Singleton<T, Atomicable>::getInstance()
{
    static_assert(std::is_same<Atomicable, $nonatomic>::value
                  || std::is_same<Atomicable, $atomic>::value, "Atomicable must be nonatomic or atomic");
 
    // 参考STL,用类型来规避 if...else...
    static T* s = __getInstance(Atomicable());
    return s;
}
 
template T* Singleton<T, Atomicable>;::__getInstance(const $nonatomic&)
{
    static std::auto_ptr auto_s;
    if (auto_s.get() == nullptr) {
        auto_s.reset(new T);
    }
    return auto_s.get();
}
 
template T* Singleton<T, Atomicable>::__getInstance(const $atomic&)
{
    static std::auto_ptr auto_s;
 
    if (auto_s.get() == nullptr) {
        static std::mutex mutex;
        mutex.lock();
        if (auto_s.get() == nullptr) {
            auto_s.reset(new T);
        }
        mutex.unlock();
    }
 
    return auto_s.get();
}
 
#define SINGLETON_DECLARE(T, ...)    \
public: \
static T* getInstance() { return Singleton<T, ##__VA_ARGS__>::getInstance(); } \
private:    \
    T();    \
    T(const T&) = delete;    \
    T&amp; operator=(const T&) = delete; \
    friend class Singleton<T, ##__VA_ARGS__>;
 
 
/******** Singleton Simple *********/
/*
 // Simple.h
 // =================================
 class Simple
 {
    SINGLETON_DECLARE(Simple, [ $nonatomic | $atomic ])
 public:
 
 };
 
 // Simple.cpp
 // =================================
 Simple::Simple()
 {
 
 }
 
 **************************************/

之所以在__getInstance(const $atomic&)函数里面对auto_s.get() == nullptr 是否为空做了两次判断,因为该方法调用一次就产生了对象,pInstance == nullptr 大部分情况下都为false,如果按照原来的方法,每次获取实例都需要加锁,效率太低。而改进的方法只需要在第一次调用的时候加锁,可大大提高效率。在第二次判断是因为,可能当mutex.lock()成功后,auto_s.get()已经不为空了。虽然概率很低,但在多线程的情况下还是要必须规避的。

实现的略有点复杂,不过用起来只用一行代码就要可以了。还有一个额外的功能是,不管什么类,通过Singleton::getInstance()都将得到一个该类的单例。也就是说你甚至可以不在类的头里声明SINGLETON_DECLARE,也可以使用单例。

释迦牟尼:最经典和灵性的4句话

495次浏览

1.无论你遇见谁,他都是在你生命中该出现的人。
这意味,没有人是因为偶然进入我们的生命。每个在我们周围,
和我们有互动的人,都代表一些事。也许要教会我们什么,也许
要协助我们改善眼前的一个情况。
  
2.无论发生什么事,那都是唯一会发生的事。
我们所经历的事,不可能以其它的方式发生,即便是最不重要的
细节也不会。 无论发生什么事,那都是唯一会发生的,而且一定
要那样发生,才能让我们学到经验以便继续前进。生命中,我们
经验的每一种情境都是绝对完美的,即便它不符我们的理解与自尊。
  
3.不管事情开始于哪个时刻,都是对的时刻。
每一件事都正好是在对的时刻开始的,不早也不晚。当我们准备
好,准备经历生命中的新奇时刻,它就在哪里,随时准备开始。
  
4.已经结束的,就已经结束了。
这是如此简单。当生命中有些事情结束,它会帮助我们进化。这
是为什么,要完整享受已然发生的事,最好是放下并持续前进。
你坐在这里,读着这些文字,我相信绝非巧合。