为什么单身人士使用指针而不使用引用?

why is singleton working with pointers but not with references?

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

有效的指针版本:

X.h

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:

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

无效的参考版本:

X.h:

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

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

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

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