2011-04-28 19 views

回答

2

C++允许的各种事物代表软件设计中的选择和妥协。对于其中的任何一点来说,没有什么内在的,绝对的邪恶(除了斯特劳斯特罗普教授认为破坏的设施可能的掷标准规范; -P)。

这个特定的代码在特定情况下是否是一个好选择取决于很多因素。例如:

  • 那里将只一个拷贝由整个程序共享
    • 可能是理想的,例如你想有一些程序范围的模式状态
    • 可怕的:代码设置/使用该值可能会发现其他代码已经修改它同时(这越来越可能随着程序变得越来越大和越来越复杂)
    • 糟糕:在多-threaded代码必须使用锁定和/或原子操作,以避免数据损坏和由此产生的错误行为和/或崩溃
  • static
    • 其他翻译单元将无法访问它
    • 它不会污染e。通过良好的IDE等

总之暴露的符号表,如果你认识到,命名空间和静态只是减少标识的冲突,他们已经得到了全局变量相关联的所有其他优点/缺点。 ...

0

对于一个它不是线程安全的。你可能想要考虑带有某种锁定的单例模式来保护它。

3

这完全取决于你需要做什么。对使用静态技术没有普遍的反感。请注意,静态本质上是单例模式,所以关于单例的所有优点/缺点都适用。

就线程而言,您必须注意,因为同一个实例可能同时被多个线程访问。如果你只需要读取数据,那么你不应该有任何问题。如果您需要修改数据,则必须担心同步。

对于代码复用和测试,singeltons通常会造成问题。例如,您不能在测试中重新创建对象,或者并行地运行多个对象。一般情况下,当我使用单例/静态时,我试着确保所有测试,并行执行等的整个生命周期的一个实例完全可以。

隐形静,你打电话给他们(只有到编译单元)是一个很好的想法。这有助于保持线程之间的同步并正确管理它们。如果他们具有全局可见性,那么他们可以在任何时候修改(私有变量不能,所以他们也是好的)。


另请注意,原子变量可以安全地从各个线程读取/写入。对于简单的计数器,这通常是一个好的解决方案:使用原子增量在C++ 0x中,你可以使用“原子”,以前使用你的操作系统/编译器功能。与单例模式一样,您可以轻松设计每个函数被同步的类,因此单例用户不必担心它。也就是说,即使在写作时,静态本身也不是线程安全的。

+0

+1“这完全取决于你需要做什么“ – 2011-04-28 07:21:54

+0

”如果您只需要读取数据,那么您不应该有任何问题“......一般来说,当另一个线程更新数据时,您无法安全地读取数据。无论程序员是否总是认为每个“一个/另一个线程”都是他们的所有权意义上的“你”所暗示的是可疑的。即使对于'int',如果你不使用某些东西来同步缓存,你可能会错过更新。 – 2011-04-28 07:24:19

+0

@Tony,我说**只需**需要**读取**。当然,你不能在没有同步的情况下写信给它。但那是我在......之后的句子中所说的? – 2011-04-28 07:45:12

1

另外,您可以在使用运行时共享库​​时使用静态类成员时遇到一些问题。例如:如果您有:

class A { 
//... 
static int staticInt; 
//... 
}; 

你这个类链接到主可执行文件,并在运行共享库,这是由该可执行文件使用(通过dlopen)在一些情况下,你可以得到分割故障由于重新初始化主要可执行文件的静态成员的副本通过加载共享库。您可以找到有关此问题的更多详细信息herethere

0

您必须注意的一个缺点是所谓的“静态初始化顺序失败”。下面是一个例子:

// foo.cpp 

class foo { 
    public: 
    static bar m_bar; 
}; 

bar foo::m_bar; 

// baz.cpp 

class baz { 
    public: 
    baz() { 
    /* some code */ 
    foo::m_bar.someMethod(); 
    } 
}; 

baz g_baz; //TROUBLE!! 

C++标准不保证关于哪个将首先被初始化的m_barg_baz。如果幸运的话,m_bar会首先被初始化,g_baz将会顺利建造。如果不是,你的程序可能会出现段错误,或者更糟。

与返回的第一次使用时构建的静态指针的方法更换m_bar规避这个问题(注:它仍然不是线程安全的):

class foo { 
    public: 
    static bar &getBar() { if(!m_barinst) m_barinst = new bar; return *m_barinst; } 
    private: 
    static bar *m_barinst; 
}; 

bar *foo::m_barinst = NULL; 
相关问题