首页 > 解决方案 > 为什么单例使用指针而不使用引用?

问题描述

我想使用引用编写一个 Meyers Singleton 类,但它不起作用。即使打印表明构造函数只被调用一次,我似乎仍然在每次调用实例访问器方法时获得类的单独实例。但是,如果我使用指针编写它,它就可以正常工作。谁能解释为什么以及如何修复参考版本?谢谢!

有效的指针版本:

Xh

class X {
    public:
        static X *getX(void);
        void ipp();
        int geti();
    private:
        X();
        int i;
};

X.cpp

#include "X.h"

X::X()
{
    printf ("X constructor\n");
    i = 0;
}

X *X::getX()
{
    static X the_only_X;
    return &the_only_X;
}

int X::geti()
{
    return (i);
}

void X::ipp()
{
    i++;
}

试试看.cpp

#include <stdio.h>
#include "X.h"

int main (int ac, char *av[])
{
    printf ("main\n");

    X *x1 = X::getX();
    x1->ipp();
    printf ("i= %d\n", x1->geti());

    X *x2 = X::getX();           // same X instance?
    x2->ipp();
    printf ("i= %d\n", x1->geti());
    x1->ipp();
    printf ("i= %d\n", x1->geti());
    x2->ipp();
    printf ("i= %d\n", x1->geti());

    return (0);
}

构建并运行,应该得到 i= 1, 2, 3, 4:

g++ -Wall X.cpp tryit.cpp && ./a.out
main
X constructor
i= 1
i= 2
i= 3
i= 4

不起作用的参考版本:

Xh:

class X {
    public:
        static X& getX(void);
        void ipp();
        int geti();
    private:
        X();
        int i;
};

X.cpp:

#include "X.h"

X::X()
{
    printf ("X constructor\n");
    i = 0;
}

X& X::getX()
{
    static X the_only_X;
    return the_only_X;
}

int X::geti()
{
    return (i);
}

void X::ipp()
{
    i++;
}

tryit.cpp:

#include <stdio.h>
#include "X.h"

int main (int ac, char *av[])
{
    printf ("main\n");

    X x1 = X::getX();
    x1.ipp();
    printf ("i= %d\n", x1.geti());

    X x2 = X::getX();           // same X instance?
    x2.ipp();
    printf ("i= %d\n", x1.geti());
    x1.ipp();
    printf ("i= %d\n", x1.geti());
    x2.ipp();
    printf ("i= %d\n", x1.geti());

    return (0);
}

构建并运行,应该得到 i= 1, 2, 3, 4:

ecd-imac27$ g++ -Wall X.cpp tryit.cpp && ./a.out
main
X constructor
i= 1
i= 1
i= 2
i= 2

标签: c++singleton

解决方案


X x1 = X::getX();正在制作单例实例的副本。也是如此X x2 = X::getX();。这意味着您实际上拥有三个. X哎呀。怎么会这样?这应该是一

如果一个单例类是可复制和/或可移动的,那么它真的不是一个单例。因此,通过从您的类中删除复制和移动操作(默认情况下由编译器提供)来强制执行:

class X {
    public:
        static X& getX(void);
        void ipp();
        int geti();

    private:
        X();

        X(const X&) = delete;             // Copy ctor
        X(X&&) = delete;                  // Move ctor
        X& operator=(const X&) = delete;  // Copy assignment
        X& operator=(X&&) = delete;       // Move assignment

        int i;
};

完成此操作后,您会发现X x1 = X::getX();X x2 = X::getX();无法编译。好的!编译器阻止您创建更多X实例。通过使用引用来解决这个问题:

X& x1 = X::getX();
X& x2 = X::getX();

一切正常:

main
X constructor
i= 1
i= 2
i= 3
i= 4

推荐阅读