摧毁单个物体

时间:2010-09-24 16:54:34

标签: c++ multithreading design-patterns oop

销毁单件对象的最佳方法是什么?

案例A:单线程环境
案例B:多线程环境

示例代码段(如果有)将非常有用。

[编辑]我没有特定的用例我只是想了解如果必须使用所有单例如何正确销毁它。据我了解,从评论中可以看出两种情况:
1.当没有代码访问它时销毁单例。(使用智能指针,它将负责使用RAII自行销毁对象)
2.退出程序时销毁单例,无论某些代码是否持有单例。 (通过在主要退出之前删除实例来明确销毁)

6 个答案:

答案 0 :(得分:9)

首先不要创建它!

说真的,我强烈建议您重新考虑您对单例的选择,尤其是在多线程环境中。相反,只需在main()中创建一个实例,然后将其传递给调用层次结构,直到需要它为止。

您可以使用类似shared_ptr的内容来确保对象保持不变,直到没有人再需要它为止。

答案 1 :(得分:2)

如果您只关心清理成功停机,可以使用atexit()

答案 2 :(得分:1)

在多线程中,

void Singleton::Destroy() 
{
  if (instance) { 
      pthread_mutex_lock(&lock);
      if (instance) { 
          delete instance;
          instance = 0x0;
      }
      pthread_mutex_unlock(&lock);
  }
}

在单线程中:

void Singleton::Destroy() 
{
  if (instance) { 
      delete instance;
      instance = 0x0;
  }
}

答案 3 :(得分:1)

对过去十年过度使用单身人士的强烈反对似乎是粗暴的健康,但他们并非完全邪恶或不合理......编程是妥协和实践,而且很难概括(通常;-P) 。通过各种方式重新审视设计,看看你是否可以有效地摆脱它们,但如果没有 - 那就这样吧。

无论如何,如果你想了解权衡,你最好不要先阅读Alexandrescu的现代C ++设计,该设计专门讨论单身人士的替代方案。基本上,你在这里问一个愚蠢的问题,因为我们不知道你的单身人员有什么操作限制......他们可能需要使用哪些潜在的互动,以及他们是否可以在关闭后重新打开等等。所以,吐出来或满足于愚蠢的答案;-P。

答案 4 :(得分:1)

不考虑这是不是一个好主意的问题 我们应该在一个单独的问题中做什么!

class S
{
    private:
        S() {}                // private constructor
        S(S const&);          // Undefined copy constructor
        S& operator(S const&) // Undefined assignment operator

    public:
        static S& getInstance()
        {
            /*
             * It is guaranteed to be built on first use
             * and correctly destroyed at the end of the application 
             */
            // Need guard for multi-threaded systems (but not on gcc)
            MULT_THREAD_GUARD;
            static S theOnlyInstance;
            return theOnlyInstance;
        }
};

对象的多线程初始化是唯一真正的问题。你可以用这两种方式处理。

  • 您可以设置GUARD以确保在执行多线程构建时只有一个线程可以进入getInstance()方法(如果您使用gcc,则不需要这样做,因为它会自动生成所需的代码以保证对象是只初始化一次)。
  • 另一种技术只是确保在创建任何线程之前初始化实例。要做到这一点,只需在main中调用getInstance()即可。请注意,如果你这样做,你也可能有一个全局变量,因为你破坏了单身人士对全局变量的主要好处(延迟初始化)。并非全局变量比单身人士好得多。

守卫示例

// Then in your platform agnostic header file
#ifndef MULTI_THREAD
#define MULT_THREAD_GUARD       /* Nothing needed in single threaded code */
#else
#if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 3 ) && (__GNUC_MINOR__ > 1)))
#define MULT_THREAD_GUARD        /* Nothing required for GCC 3.2 onwards */
#elif defined(YOUR_COMPILERS_MACRO)
#define MULT_THREAD_GUARD        do { /* Put compiler lock code here */ } while (false)
#else
#error "ADD MULTI Thread GUARD for you compiler here"
#endif

答案 5 :(得分:1)

如果你打算使用全局,我更喜欢这样的东西:

class GlobalThing{ /* ... */ };

GlobalThing *global_thing = 0;

// ...

int main(){
  GlobalThing gt(/* ... */);
  global_thing = >

  // create threads
  // ...
  // kill threads
}

这会给你:

  1. 全局对象的易于识别的生命周期。
  2. 以典型的RAII方式清理资源。
  3. 以上几点意味着它可以在多线程环境中工作,而不必担心锁定等,因为在gt的生命周期之前或之后不存在线程。好吧,在某些环境中,你可以退出main(),其他线程将继续运行,但这是一种以各种原因构建程序的可怕方法。
  4. 你仍然需要担心:

    1. 全局变量的初始化顺序。但是,这与Static Initialization (and Destruction) Order Fiasco不同,因为这种技术为您提供了定义全局变量初始化和销毁​​顺序的好处(如果您以这种方式定义它们)。
    2. 别的,我敢肯定。