2012-05-29 4 views
0

У меня есть очень конкретный вопрос о динамически распределенном статическом глобальном объекте. В моем проекте у меня мало объектов, к которым мне нужно получить доступ из разных мест по потокам на протяжении всей жизни приложения. Я хочу создать при инициализации и отключении приложения, когда приложение завершит работу. Так что я попытался следующие,Global Static Динамически выделенные объекты C++

Header File: 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. Где бы был создан объект Heap (поскольку я использую новую) или глобальную память (поскольку я использую статическую)? Или я нарушаю принцип ООП?
  4. Можно ли вызвать MyObjectFactory :: GetMyObject() из нескольких потоков?
  5. Это хороший способ добиться чего-то подобного Синглтона?

Пожалуйста, дайте мне знать ваши данные.

Большое вам спасибо!

+0

'MyObject *' является указателем, а не ссылкой ... –

+0

Либо «статический», либо «динамический», вы не можете иметь оба. –

+0

Существует ли конкретное требование создания объекта с помощью 'new'? В противном случае просто сделайте глобальным «MyObject theObject;». –

ответ

2

Объект будет создан только один раз, а затем ссылка на объект будет возвращена. (Я хочу это, потому что MyObject инкапсулировать несколько системных ресурсов, как текстовый файл)

  • MyObject* является тип указателя, а не ссылочный тип. gMyObject - это переменная типа указатель на MyObject.

MyObject уничтожается, когда приложение завершается.

  • Это не делает, никто не называет delete на указатель, так что вы имеете утечку.

Где бы созданный объект Heap (как я использую новую) или глобальную память (как я использую статический)? Или я нарушаю принцип ООП?

  • Если вы используете new, объект создается на 'куче'. static применим только к указателю на объект, а не по самому объекту.

Это нормально называть MyObjectFactory :: GetMyObject() из нескольких ниток?

  • Это не так, вы можете вызвать несколько инициализацию, если у вас есть параллельные потоки и объект еще не был построен.

Это хороший способ добиться чего-то подобного Синглтона?

  • Это не так. Или, может быть, это так, но синглтон, как правило, плохой способ добиться чего-то (и я только сказал обычно).
+0

Точнее, 'MyObject *' - это тип, но теперь я педант. –

+0

@phresnel: Педантизм принят, отредактирован ответ. –

+0

Мне стыдно продолжать педантику, прошу прощения. Но 'gMyObject' - это указатель. Могу ли я предложить «gMyObject - это переменная типа« Указатель на MyObject ». Чувствую себя плохо. Игнорируй меня. Или, может быть, 'gMyObject - это указательная переменная'. –

2

Стандартный способ достижения как надлежащее разрушения и правильная инициализации с минимальной головной болью использует блок-местные статики, как это:

foo.hpp:

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

foo.cpp :

#include "foo.hpp" 

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

Теперь вы можете сказать Foo::get() в любом месте вашего кода. Никаких указателей, динамических распределений и ничего не происходит. Поистине статический синглтон.

+0

Вы можете добавить что-то, что связано с безопасностью потоков и как отличаются C++ 11 и C++ 03, в соответствии с вопросом №4 OP. –

+0

@ K-ballo: Инициализация потокобезопасна, а все остальное - проблема OP. (Но это не имеет ничего общего с синглтоном. Это просто общее программирование.) –

+0

Является ли построение комплексного 'Foo' потокобезопасным? Не было ли условия гонки в C++ 03? –

0

Объект будет создан только один раз, а затем ссылка на объект будет возвращена.

Если ваша программа однопоточная, да (хотя в вашем примере она возвращает указатель не ссылку). В противном случае существует опасность создания двух потоков, создающих отдельные копии объекта; или на самом деле что-либо еще происходит, поскольку в этом случае поведение не определено.

MyObject уничтожается, когда приложение завершается.

Нет, объекты, созданные с new будут уничтожены только delete, никогда автоматически, так что этот объект является утечка. Независимо от того, является ли это проблемой, зависит от того, автоматически ли все ресурсы, которые он использует, автоматически.

Где бы был создан объект Heap (поскольку я использую новую) или глобальную память (поскольку я использую статическую)?

Объект выделяется из бесплатного магазина (aka heap); указатель на него статичен.

Можно ли вызвать MyObjectFactory :: GetMyObject() из нескольких потоков?

Только если вы можете гарантировать, что объект уже создан, прежде чем любой из них его вызовет.

Это хороший способ добиться чего-то подобного Синглтона?

В C++ нет хорошего способа достичь этого. Наилучший подход заключается в том, чтобы вообще избегать общедоступных объектов; создать его где-нибудь и передать ссылки на все, что ему нужно.

Если вы действительно хотите, глобальный объект, то есть несколько вариантов, каждый со своим собственным deathtraps:

  • Простого глобальным объектом. Будьте осторожны с Инициализационным заказом Fiasco, если у вас есть более одного из них, с зависимостями между ними.
  • Функция, содержащая статический объект, возвращающая ссылку на это. Это гарантированно будет инициализировано при его использовании и является потокобезопасным в реализации, совместимой с C++ 11 (и во многих предыдущих реализациях тоже). Однако во время выключения программы существует опасность, что она может быть уничтожена перед другими статическими объектами, которые все еще пытаются получить к ней доступ - возможно, вы можете избежать этого путем динамического выделения и утечки объекта, как в вашем подходе. Кроме того, для обеспечения потокобезопасной конструкции могут быть некоторые потоки времени выполнения.
  • Лично назначенный динамический объект (как и у вас), если вы либо убедитесь, что он инициализирован перед запуском нескольких потоков, либо добавьте безопасность потока (что не совсем прямолинейно и добавит дополнительные служебные данные).
Смежные вопросы