C++设计模式-Singleton----static+++++++const

来源:互联网 发布:药智网数据查询 编辑:程序博客网 时间:2024/06/17 15:53
#ifndef _SINGLETON_H_
#define _SINGLETON_H_


class Singleton
{

private:

 //定义一个私有的静态全局变量来保存该类的唯一实例 
    static Singleton* pInstance;//静态成员,保存对象的唯一实例

 /// 构造函数必须是私有的 
        /// 这样在外部便无法使用 new 来创建该类的实例 

    Singleton();//私有化构造函数,使其无法在类外实例化

public:

      /// 定义一个全局访问点 
        /// 设置为静态方法 
        /// 则在类的外部便无需实例化就可以调用该方法 

    static Singleton* Instance();
    //void Destroy();
    static void Destroy();
};


#endif

===============================================================================================================

===============================================================================================================

#include "Singleton.h"
#include <iostream>


using namespace std;


Singleton* Singleton::pInstance = NULL;


Singleton::Singleton()
{
    cout<< "Singleton..." << endl;
}

//尽管我两次访问了 GetInstance(),但是我访问的只是同一个实例,
Singleton* Singleton::Instance()
{

   //这里可以保证只实例化一次 
            //即在第一次调用时实例化 
            //以后调用便不会再实例化
 

    if(NULL == pInstance)
    {
        pInstance = new Singleton();
    }
    return pInstance;
}


void Singleton::Destroy()
{
    delete pInstance;
    pInstance = NULL;
    cout<< "Destroy..." << endl;
}

==============================================================================================

=============================================================================================

#include "Singleton.h"
#include <iostream>


using namespace std;


int main()
{
    Singleton* ps = Singleton::Instance();//通过全局访问点获取实例
    Singleton::Destroy();
    return 0;
}

000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

class Singleton{   public:       static Singleton* getInstance( );       ~Singleton( );   private:       Singleton( );       static Singleton* instance;};
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

const和类

(1)const修饰成员变量
const修饰类的成员函数,表示成员常量,不能被修改,同时它只能在初始化列表中赋值。
    class A
    { 
        …
        const int nValue;         //成员常量不能被修改
        …
        A(int x): nValue(x) { } ; //只能在初始化列表中赋值
     }


(2)const修饰成员函数
const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰。
    class A
    { 
        …
       void function()const; //常成员函数, 它不改变对象的成员变量.                       

//也不能调用类中任何非const成员函数。
}

对于const类对象/指针/引用,只能调用类的const成员函数,因此,const修饰成员函数的最重要作用就是限制对于const对象的使用。

a. const成员函数不被允许修改它所在对象的任何一个数据成员。

b. const成员函数能够访问对象的const成员,而其他成员函数不可以。

(3)const修饰类对象/对象指针/对象引用

·             const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。

·             const修饰的对象,该对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企图。
例如:
class AAA

    void func1(); 
void func2() const; 

const AAA aObj; 
aObj.func1(); ×
aObj.func2(); 正确

const AAA* aObj = new AAA(); 
aObj-> func1(); ×
aObj-> func2(); 正确





000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

举了一些

C/C++

中用到

const

的地方。

 

1

const

变量

 

2

const

指针

 

3

const

引用

 

4

const

 

5

,类的

const

成员变量

 

6

,类的

const

成员函数

 

7

const

修饰函数的形参与返回值

 

下面我们分别讨论上面几种情况下,

const

的用法。

举了一些

C/C++

中用到

const

的地方。

 

1

const

变量

 

2

const

指针

 

3

const

引用

 

4

const

 

5

,类的

const

成员变量

 

6

,类的

const

成员函数

 

7

const

修饰函数的形参与返回值

 

下面我们分别讨论上面几种情况下,

const

的用法。


举了一些C/C++中用到const的地方。 
1,const变量
 2,const指针 
3,const引用
 4,const类 
5,类的const成员变量 
6,类的const成员函数 
7,const修饰函数的形参与返回值 
、、、、、、、、、、、、、、、、、、、、、、、、、
const引用引用引用引用引用引用引用
-------------------------------------基础知识1

int a=10;

int &b=a;//声明b是a的引用,这样a的值变以后,b的值也变;b的值变以后,a的值也跟着变。

------------------------------------基础知识2

int ival=1024;

int *pi=&ival;    //pi指向一个int型的数

int **ppi=&pi;   //ppi指向一个int型的指针

---------------------基础知识3

类的const数据成员

        在类内部,const数据成员代表在对象的生命周期内该数据成员不可更改,也就是说这个const修饰的是该对象的一个数据,它是属于对象的,只有在该对象的有效期内起作用


2、类的static数据成员

        在类内部,static数据成员代表了属于整个类的数据,并不属于单个对象,因此它在整个程序的运行过程中只有一个副本,不能在定义对象时对static成员进行初始化,就是不能用构造函数进行初始化。

------------------基础知识4

重载操作符的三个准则
1.右端值要为const 类型(不想改变他的值)Take a const-reference for the argument (the right-hand side of the assignment).
2.要返回一个引用,以便于实现(a=b=c…… (Do this by returning *this.)

3.检查是否为自我赋值Check for self-assignment, by comparing the pointers (this to &rhs).

------------------基础知识5

C++中,若类的方法前加了static关键字,则该方法称为静态方法,反之为实例方法。静态方法为类所有,可以通过对象来使用,也可以通过类来使用。但一般提倡通过类名来使用,因为静态方法只要定义了类,不必建立类的实例就可使用。静态方法只能用类的静态成员


、、、、、、、、、、、、、、、、、、、、、、、、、、
int  ival = 1092;
int &re =ival;
int &re2 = &ival;//错误
int *pi=&ival;
int *&pi2 = pi;
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
double  dval=3.134
//下3行仅对const引用才是合法的
const int &ir=1024
const int &ir2=dval;
const double &dr=dval+1.0
、、、、、、、、、、、、、、、、、、、、、、、、、、
int iv=100;
int  *&pir=&iv;//错误,非const引用对需要临时对象的引用
int *const &pir=&iv;

const int ival = 1024;

int *&pi_ref = &ival;    //错误,非const引用是非法的

const int *&pi_ref = &ival;   //错误,需要临时变量,且引用的是指针,而pi_ref是一个非常量指针

const int * const &pi_ref = &ival;  //正确

//补充

const int *p = &ival;

const int *&pi_ref = p;  //正确

、、、、、、、、、、、、、、、、、、、、、、、、、、、、

1.不允许非const引用指向需要临时对象的对象或值

int a = 2;

int &ref1 = a;// OK.有过渡变量。

const int &ref2 = 2;// OK.编译器产生临时变量,需要const引用

2.地址值是不可寻址的值

int * const &ref3 = &a;   // OK;

3.于是,用const对象的地址来初始化一个指向指针的引用

    const int b = 23;

    const int *p = &b;

    const int *& ref4 = p;

    const int *const & ref5 = &b;   //OK

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

下面我们分别讨论上面几种情况下,const的用法。

class S{    public:        static S& getInstance()        {            static S    instance; // Guaranteed to be destroyed.                                  // Instantiated on first use.            return instance;        }    private:        S() {}                    // Constructor? (the {} brackets) are needed here.        // C++ 03        // ========        // Dont forget to declare these two. You want to make sure they        // are unacceptable otherwise you may accidentally get copies of        // your singleton appearing.
//,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量        S(S const&);              // Don't Implement        void operator=(S const&); // Don't implement//操作符重载        // C++ 11        // =======        // We can use the better technique of deleting the methods        // we don't want.    public:        S(S const&)               = delete;        void operator=(S const&)  = delete;        // Note: Scott Meyers mentions in his Effective Modern        //       C++ book, that deleted functions should generally        //       be public as it results in better error messages        //       due to the compilers behavior to check accessibility        //       before deleted status};
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

private static Drawable sBackground;


@Override
protectedvoid onCreate(Bundle state){
  super.onCreate(state);
  
  TextView label =newTextView(this);
  label.setText("Leaks are bad");
  
  if(sBackground ==null){
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);
  
  setContentView(label);
}


上面几行代码,内存泄露挺严重的。sBackground是一个 static 变量,在 label调用setBackgroundDrawable的时候,会调用sBackground的setCallback,所以在sBackground中就存在label的引用。

而,label中又存在Activity的引用,所以此Activity一直不会被回收,即使已经finish了。


如何避免:

  1. 使用applicationContext作为上下文,避免使用activity
  2. 设置Drawable的Callback为null
  3. 在Service或者Activity使用内部类尽量使用static类。例如:使用Handler


实用的Bean工厂ApplicationContext
ApplicationContext的中文意思是“应用前后关系”,它继承自BeanFactory接口,除了包含BeanFactory的所有功能之外,在国际化支持、资源访问(如URL和文件)、事件传播等方面进行了良好的支持,被推荐为Java EE应用之首选,可应用在Java APP与Java Web中。

关于第3点,看个例子:

复制代码
 1    static class IncomingHandlerextendsHandler { 2         private final WeakReference<UDPListenerActivity> mActivity; 3   4         IncomingHandler(UDPListenerActivity activity) { 5             mService = newWeakReference < UDPListenerActivity > (activity); 6         } 7   8         @Override 9         public void handleMessage(Message msg) {10             UDPListenerActivity activity = mActivity.get();11             if (activity != null) {12                 activity.handleMessage(msg);13             }14         }15    } 
复制代码
我们知道,Message发出之后是存在MessageQueue中的,有些Message也不是马上就被处理的。在Message存在一个 target,是Handler的一个引用,如果Message在Queue中存在的时间越长,就会导致Handler无法被回收。如果Handler是非静态的,则会导致Activity或者Service不会被回收。
所以正确处理Handler等之类的内部类,应该采用上述代码。

 


222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

很多地方我们需要使用到Context,比如我们自定义一个单例的CustomManager,当我们使用一些系统的服务时,就需要Context参数,这时如果使用Activity或者Service 作为context,就会容易造成内存泄露。 
具体原因请看下面的这个例子:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">pubic class CustomManager {    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> CustomManager sInstance;    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> CustomManager <span class="hljs-title" style="box-sizing: border-box;">getInstance</span>(Context context) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (sInstance == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这个类拥有了一个静态的context引用        </span>            sInstance = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> CustomManager(context);        }        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> sInstance;    }    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Context mContext;    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-title" style="box-sizing: border-box;">CustomManager</span>(Context context) {        mContext = context;    }}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>

当所持有的Context的引用是一个Activity或者Service,系统销毁它们后,由于CustomManager中有其静态的引用,所以Activity或者Service所占用的资源并不会被回收,造成内存泄露。 
那么正确的方法是使用Application的context, 因为Application的context是单例的,并且它的生命周期属于整个应用进程。所以上边的代码需要改成:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> CustomManager sInstance;    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> CustomManager <span class="hljs-title" style="box-sizing: border-box;">getInstance</span>(Context context) {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (sInstance == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这个类拥有了一个静态的context引用        </span>             sInstance = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> CustomManager(context.getApplicationContext());        }        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> sInstance;    }    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Context mContext;</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

0 0
原创粉丝点击