您的位置:首页 > 编程语言 > C语言/C++

从零开始学C++之对象的使用(三):static 与单例模式、auto_ptr与单例模式、const 用法小结、mutable修饰符

2015-03-04 23:06 507 查看
转:/article/1350629.html

一、static 与单例模式

单例模式也就是简单的一种设计模式,它需要:

保证一个类只有一个实例,并提供一个全局访问点

禁止拷贝

C++ Code
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

#include <iostream>

using namespace std;

class Singleton

{

public:

static Singleton *GetInstance()

{

if (instance_ == NULL)

{

instance_ = new Singleton;

}

return instance_;

}

~Singleton()

{

cout << "~Singleton ..." << endl;

}

private:

Singleton(const Singleton &other);

Singleton &operator=(const Singleton &other);

Singleton()

{

cout << "Singleton ..." << endl;

}

static Singleton *instance_;

};

Singleton *Singleton::instance_;

int main(void)

{

//Singleton s1;

//Singleton s2;

Singleton *s1 = Singleton::GetInstance();

Singleton *s2 = Singleton::GetInstance();

//Singleton s3(*s1); // 调用拷贝构造函数

return 0;

}
上述程序虽然调用了两个GetInstance函数,但只调用一次构造函数,即创建一个对象。将赋值运算符和拷贝构造函数声明为私有,禁止拷贝。但程序存在一个问题就是对象生存期到时不会被析构。

为了解决对象不会被析构的问题,可以使用一个静态的嵌套类对象来解决:

C++ Code
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

#include <iostream>

using namespace std;

class Singleton

{

public:

static Singleton *GetInstance()

{

if (instance_ == NULL)
{

instance_ = new Singleton;
}

return instance_;
}

~Singleton()

{

cout << "~Singleton ..." << endl;

}

//static void Free()

//{

// if (instance_ != NULL)
// {

// delete instance_;
// }

//}

class Garbo

{

public:

~Garbo()

{

if (Singleton::instance_ != NULL)
{

delete instance_;
}

}

};

private:

Singleton(const Singleton &other);

Singleton &operator=(const Singleton &other);

Singleton()

{

cout << "Singleton ..." << endl;

}

static Singleton *instance_;

static Garbo garbo_; // 利用对象的确定性析构

};

Singleton::Garbo Singleton::garbo_;

Singleton *Singleton::instance_;

int main(void)

{

//Singleton s1;

//Singleton s2;

Singleton *s1 = Singleton::GetInstance();

Singleton *s2 = Singleton::GetInstance();

//Singleton s3(*s1); // 调用拷贝构造函数

return 0;

}
利用静态嵌套对象的确定性析构会调用Garbo类的析构函数,在析构函数内delete 单例类的指针。

上面办法比较繁琐,也可以返回局部静态对象的引用来解决:

C++ Code
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

#include <iostream>

using namespace std;

class Singleton

{

public:

static Singleton &GetInstance()

{

static Singleton instance; // 局部静态对象

return instance;

}

~Singleton()

{

cout << "~Singleton ..." << endl;

}

private:

Singleton(const Singleton &other);

Singleton &operator=(const Singleton &other);

Singleton()

{

cout << "Singleton ..." << endl;

}

};

int main(void)

{

Singleton &s1 = Singleton::GetInstance();

Singleton &s2 = Singleton::GetInstance();

return 0;

}
局部静态对象只会初始化一次,所以调用多次GetInstance函数得到的是同一个对象。由于函数内使用了静态对象,故不是线程安全的。实际上也可以使用auto_ptr 智能指针 来解决,程序如下,更详细的对auto_ptr 的讨论参见这里

C++ Code
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

#include <iostream>

#include<memory>

using namespace std;

class Singleton

{

public:

static Singleton *GetInstance()

{

if (instance_.get() == NULL)

{

instance_ = auto_ptr<Singleton>(new Singleton);

}

return instance_.get();

}

~Singleton()

{

cout << "~Singleton ..." << endl;

}

private:

Singleton(const Singleton &other);

Singleton &operator=(const Singleton &other);

Singleton()

{

cout << "Singleton ..." << endl;

}

static auto_ptr<Singleton> instance_;

};

auto_ptr<Singleton> Singleton::instance_;

int main(void)

{

//Singleton s1;

//Singleton s2;

Singleton *s1 = Singleton::GetInstance();

Singleton *s2 = Singleton::GetInstance();

//Singleton s3(*s1); // 调用拷贝构造函数

return 0;

}
实际上,上述所有的单例模式例子都不是线程安全的,设想如果两个线程同时运行到语句if (instance
== null),而此时该实例的确没有创建,那么两个线程都会创建一个实例。如果不希望加锁实现线程安全,可以使用饿汉模式(即在main函数之前先生成一个实例):



或者通过加锁方式实现,请参考这里

二、const成员函数、const 对象、mutable修饰符

(一)、const 成员函数

const成员函数不会修改对象的状态

const成员函数只能访问数据成员的值,而不能修改它

(二)、const 对象

如果把一个对象指定为const,就是告诉编译器不要修改它

const对象的定义:

const 类名 对象名(参数表);

const对象不能调用非const成员函数

用mutable修饰的数据成员即使在const对象或在const成员函数中都可以被修改。

C++ Code
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

#include <iostream>

using namespace std;

class Test

{

public:

Test(int x) : x_(x), outputTimes_(0)

{

}

int GetX() const

{

cout << "const GetX ..." << endl;

//x_ = 100;

return x_;

}

int GetX()

{

cout << "GetX ..." << endl;

return x_;

}

void Output() const

{

cout << "x=" << x_ << endl;

outputTimes_++;

}

int GetOutputTimes() const

{

return outputTimes_;

}

private:

int x_;

mutable int outputTimes_;

};

int main(void)

{

const Test t(10);

t.GetX();

Test t2(20);

t2.GetX();

t.Output();

t.Output();

cout << t.GetOutputTimes() << endl;

return 0;

}


三、const 用法总结

可以对const 的用法做个小总结:



参考:

C++ primer 第四版

Effective C++ 3rd

C++编程规范
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐