0

我对动态分配的静态全局对象有非常具体的问题。在我的项目中,我几乎没有需要在整个应用程序生命周期中跨线程从不同位置访问的对象。我想在应用程序初始化时创建并在应用程序退出时销毁。所以我尝试了以下,

头文件:MyObjectFactory.h

class MyObjectFactory{
   public:
      static MyObject* GetMyObject();
};

源文件:MyObjectFactory.cpp

static MyObject* gMyObject = 0;

MyObject* MyObjectFactory::GetMyObject(){
    if(gMyObject == 0)
    {
        gMyObject = new MyObject();
    }
    return gMyObject;
}

这段代码似乎可以工作,但我想清除一些东西。

  1. 对象只会被创建一次,然后将返回对对象的引用。(我想要这个,因为 MyObject 封装了一些系统资源,如文本文件)
  2. 当应用程序退出时,MyObject 被销毁。
  3. 对象创建堆(当我使用 new 时)或全局内存(当我使用静态时)会在哪里?还是我违反了任何 OOP 原则?
  4. 可以从多个线程调用 MyObjectFactory::GetMyObject() 吗?
  5. 这是实现有点类似于 Singleton 的好方法吗?

请让我知道您的意见。

太感谢了!

4

3 回答 3

2

以最小的麻烦实现正确销毁和正确初始化的标准方法使用块局部静态,如下所示:

foo.hpp:

struct Foo
{
    static Foo & get();
    // ...
};

foo.cpp:

#include "foo.hpp"

Foo & Foo::get()
{
    static Foo impl;
    return impl;
}

现在您可以Foo::get()在代码中的任何位置说。没有指针,没有动态分配,也没有任何东西被泄露。一个真正的静态单例。

于 2012-05-29T15:46:47.700 回答
2

对象只会被创建一次,然后将返回对对象的引用。(我想要这个,因为 MyObject 封装了一些系统资源,如文本文件)

  • MyObject*是指针类型,而不是引用类型。gMyObject是指向 的类型指针的变量MyObject

当应用程序退出时,MyObject 被销毁。

  • 它没有,没有人调用delete你的指针,所以你有泄漏。

对象创建堆(当我使用 new 时)或全局内存(当我使用静态时)会在哪里?还是我违反了任何 OOP 原则?

  • 如果您正在使用new,则在'heap'中创建对象。static仅适用于指向您的对象的指针,而不适用于对象本身。

可以从多个线程调用 MyObjectFactory::GetMyObject() 吗?

  • 不是,如果您有并发线程并且尚未构造对象,则可能会导致多次初始化。

这是实现有点类似于 Singleton 的好方法吗?

  • 它不是。或者也许是这样,但是单例通常是实现某事的不好方法(我只说通常)。
于 2012-05-29T15:46:24.340 回答
0

对象只会被创建一次,然后将返回对对象的引用。

如果您的程序是单线程的,则可以(尽管在您的示例中它返回的是指针而不是引用)。否则存在两个线程创建对象的单独副本的危险;或者实际上发生了其他任何事情,因为在这种情况下行为是未定义的。

当应用程序退出时,MyObject 被销毁。

不,用 创建的对象new只会被 销毁delete,永远不会自动销毁,所以这个对象被泄露了。这是否是一个问题取决于它使用的所有资源是否都被系统自动回收。

对象创建堆(当我使用 new 时)或全局内存(当我使用静态时)会在哪里?

对象是从空闲存储区(又名堆)分配的;指向它的指针是静态的。

可以从多个线程调用 MyObjectFactory::GetMyObject() 吗?

仅当您可以确保在他们中的任何一个调用它之前已经创建了该对象。

这是实现有点类似于 Singleton 的好方法吗?

在 C++ 中没有很好的方法来实现这一点。最好的方法是完全避免全局可访问的对象;在某处创建它,并将引用传递给任何需要它的东西。

如果你真的想要一个全局对象,那么有几个选项,每个选项都有自己的死亡陷阱:

  • 一个简单的全局对象。如果您有多个其中之一,并且它们之间存在依赖关系,请注意初始化顺序惨败。
  • 一个包含静态对象的函数,返回对 this 的引用。这保证在您使用它时会被初始化,并且在符合 C++11 的实现上是线程安全的(在许多早期的实现上也是如此)。但是,在程序关闭期间,它可能会在其他仍在尝试访问它的静态对象之前被破坏 - 您可以通过动态分配和泄漏对象来避免这种情况,就像您的方法一样。确保线程安全的构造也可能会产生一些运行时开销。
  • 一个延迟分配的动态对象(就像您拥有的那样),只要您确保在启动多个线程之前对其进行初始化,或者添加线程安全性(这并不完全简单,并且会增加运行时开销)。
于 2012-05-29T15:55:14.790 回答