【问题标题】:singleton with pointers require me to declare instance as public static带指针的单例需要我将实例声明为公共静态
【发布时间】:2013-05-21 23:33:54
【问题描述】:

我正在尝试学习单例模式,但遇到了设计困境。

一个正常工作的单例如下所示: 注意 static myClass * mc;公开,就像 public static myClass * getInstance

1) 工作代码

#include "iostream"
using namespace std;

class myClass {
private:  
   myClass() {          
   }
 void   operator = (const myClass &);
 myClass (const myClass & );

public:
   static myClass * mc;
   static myClass * getInstance () {
       cout << "\n getInstance  callsed \n";
       if (mc == NULL) {
           mc = new myClass();
       }
       return mc;
    }

 void print() {
     cout <<"\n call to print donem \n";
 }

};
myClass * myClass::mc =NULL;

int main() {    
    myClass * mc = myClass::getInstance ();
    mc->print();
    return 0;
}

2) NOT_WORKING_CODE

导致编译器错误的不工作实例。请注意,我试图将static myClass * mc; 保密

#include "iostream"
using namespace std;

class myClass {
private: 
   static myClass * mc;
   myClass() {        
   }
 void   operator = (const myClass &);
 myClass (const myClass & );

public:
    static myClass * getInstance () {
        cout << "\n getInstance  callsed \n";
        if (mc == NULL) {
            mc = new myClass();
        }
        return mc;
    }

 void print() {
    cout <<"\n call to print donem \n";
 }

};

int main() {

    myClass * mc = myClass::getInstance ();
    mc->print();
    return 0;
}

输出: 在函数main': undefined reference tomyClass::mc' 对 `myClass::mc' 的未定义引用

问题:

1) 为什么我收到上述 NOT_WORKING_CODE 的错误

2) 我认为使用 public myClass::mc 是违反设计规则的,因为我们应该只将接口设为 public 。这里我面临的问题是上面工作代码1)的用户可以直接访问myClass::mc来调用一些函数,比如print myClass::mc->print();没有第一个调用实例..

即当我在上面的1)中更改以下内容时

int main() {
    myClass::mc->print();
    myClass * mc = myClass::getInstance ();
    mc->print();
    return 0;
}

打印出来我吓坏了

call to print donem 

 getInstance  callsed 

 call to print donem 

即,我可以在没有有效实例的情况下调用,因为该实例是在 getInstance 中创建的。这意味着如果 print 正在访问某些指针等,我很可能会遇到一些异常。

因此这表明 1) 存在设计缺陷。如何纠正同样的问题......

【问题讨论】:

  • 无论它是否是私有的,您仍然需要通过将其设置为 NULL 来实例化它。

标签: c++ pointers singleton


【解决方案1】:

//myClass * myClass::mc =NULL; 出现错误是因为您注释掉了该行,而不是因为您将变量设为私有。因此,要使代码与变量 private 一起工作,只需不要注释掉该行,它就会编译。

请看这里:What is an undefined reference/unresolved external symbol error and how do I fix it?

但是你不应该以这种方式使用单例模式。事实上,尽量避免使用单例,如果你真的必须使用它们,请使用 Meyers Singleton(谷歌搜索!)

【讨论】:

  • 我更关心我的第二点,即如何使这个实现更安全......我已经给出了一个工作代码作为第 1 点)..
  • 正如我所说,该错误与私有变量无关。意思是,您可以修复错误并将变量保留为私有且相对“保存” wrt。使用权。但它不是线程安全的。
  • @Arne Mertz,有人写了一本书说“不要使用单例”。它变成了一种宗教。如果使用得当,Singleton 完全可以并且很有用。顺便说一句,线程安全与否,它与这个主题无关。
  • @user1764961 我在回答的第一行中谈到了这个主题。其他行只是进一步的信息。学习静态指针单例,如果并发时会咬你,那是没有意义的,而迈耶斯单例则更简单,避免了线程安全问题和该线程的问题。 Wrt 宗教 - 我没有说“宗教上不”,我说“避免”。当然,在少数情况下,Singleton 还可以并且有用,但它们经常被过度使用并引入不必要的问题和耦合。
  • @MAG 您可以(并且经常必须)在类定义之外定义静态类成员,而不管它们的访问修饰符如何。您可以这样做,因为它是一个定义,而不是访问。函数也是如此:您可以在类定义之外的 .cpp 中定义 void foo::bar() {},尽管它是私有的。
【解决方案2】:

mc 是一个静态数据成员,因此它必须像您在第一个案例中所做的那样显式初始化。

myClass * myClass::mc =NULL;

在第二种情况下你错过了这样做。

查看此链接http://www.parashift.com/c++-faq/link-errs-static-data-mems.html

顺便说一句,这是链接器错误而不是编译器错误。

【讨论】:

    猜你喜欢
    • 2021-11-23
    • 2017-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多