2010-04-01 3 views
8

Обязательно иметь частный деструктор для одноэлементного класса.частный деструктор для одноэлементного класса

+1

Нет, это не так. Почему вы спрашиваете? Кто вас заставит? И задавать вопросы, у которых есть ответ «да/нет», не очень хорошая идея. – 2010-04-01 10:45:24

+2

По крайней мере, такие вопросы не могут быть закрыты для аргументации. ':)' – sbi

+0

@sbi: «C++ - это груз старого мусора, я прав?» ;-) –

ответ

6

Это может быть не то, что вы ищете .. Но для справки, я использую его следующим образом:

// .h 
class Foo { 
public: 
    static Foo* getInstance(); 
    static void destroy(); 
private: 
    Foo(); 
    ~Foo(); 

    static Foo* myInstance; 
}; 

// .cpp 
Foo* Foo::myInstance = NULL; 

Foo* Foo::getInstance(){ 
    if (!myInstance){ 
     myInstance = new Foo(); 
    } 
    return myInstance; 
} 
void Foo::destroy(){ 
    delete myInstance; 
    myInstance = NULL; 
} 

Затем в конце моей программы, я называю уничтожить на объекте. Как указывает Петтер, система вернет память, когда ваша программа закончится, поэтому нет реальной причины. Причина, по которой я использую уничтожение, - это когда Ogre жаловался, что я не выпустил всю память, которую я выделил. После этого я просто использую его как «хорошую манеру», так как мне нравится убираться после себя.

+1

Когда вы явно предоставляете 'destroy', вы также обеспечиваете простую абстракцию. Вы должны посмотреть Alexandrescu «Modern C++ Design» и вдохнуть вдохновение в «Loki :: Singleton». –

+2

Возможно, вы захотите зарегистрировать destroy с atexit. –

+0

Что я могу получить с books.google.com, так это то, что * при уничтожении singleton я должен удалить его при завершении приложения *. Но мне любопытно, что вы подразумеваете под пропущенной абстракцией. Должен ли я создать новый вопрос, возможно ...? :) Было бы все равно, если я сделаю это, как предлагает Майкл Аарон? – Default

4

Все классы имеют деструктор. Если вы его не создадите, компилятор сделает это за вас. Таким образом, ваш вопрос может быть изменен: имеет ли деструктор для одноэлементного класса частный?

Простой ответ: нет, это не обязательно.

Более интересный вопрос: полезно ли сделать деструктор одноэлементного класса частным?

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

+0

Если ваш синглтон никогда не копируется (чего не должно быть, поскольку это сделает его уже не одиночный), он никогда не может выпасть из сферы действия, что означает, что деструктор никогда не может быть вызван в первую очередь (даже случайно). –

+2

@Travis: он может: 'GetSingleton() -> ~ CSingleton()' – MSalters

+0

@MSalters, но кто в здравом уме сделал бы такое? IMHO, любой код, который вызывает деструктор явно и не использует размещение new, очень подозрительный. –

11

Если синглтон реализован как переменная в глобальном масштабе, он должен иметь общественный деструктор. Доступны только общедоступные члены в глобальном масштабе.

Если он объявлен как статический член или статический локальный в своем собственном классе, деструктор может быть закрытым. Деструктор вызывается изнутри класса, где он доступен, когда программа выходит. Это один из способов обеспечения того, чтобы объект был одиночным. Нужно ли вам усиленно это применять? Если да, да. Это зависит от того, что вы подразумеваете под «обязательным».

class A{ 
private: 
    ~A() {} 
public: 
    static A &getGlobalA() { 
     static A a2; // <- or here - better technique 
     return a2; // this is initialized upon 1st access 
    };    // and destroyed on program exit 

    static A a; // <- constructor, destructor accessed from here 
}; 

A A::a; // <- but "called" from here in terms of control flow 
+0

Фактический локальный 'static' является одним из самых удобных способов. Каков эффект вызова 'getGlobalA' после того, как' a2' был уничтожен (во время уничтожения глобалов)? Я боюсь, что это приведет к UB. –

+0

@Matthieu m: См. Эту статью для простой техники для устранения этой проблемы: http://stackoverflow.com/questions/335369/finding-c-static-initialization-order-problems/335746#335746 –

1

Вы можете вернуть ссылку на экземпляр singleton.

class Factory : public IFactory 
    { 
    private: 
     /** 
     * This class should not be instantiated through its constructor. Since, it implements 
     * Singleton pattern. 
     */ 
     Factory();  
    public: 
     virtual ~Factory(); 
     /** 
     * Accessor method for singleton instance. 
     * \note use this static method to access to operations of this class. 
     */ 
     static IFactory& instance(){ 
      if(!m_instance.get()){ 
       m_instance.reset(new Factory());  
      } 
      return static_cast<IFactory&>(*m_instance); 
     } 
     /** 
     * \see IFactory::create 
     */ 
     virtual boost::shared_ptr<IConnector> create(); 
    private: 
     /* Singleton instance */ 
     static boost::scoped_ptr<Factory> m_instance; 

    }; 
+0

Помимо того факта, что 'static_cast' не нужен (вы можете неявно преобразовывать из производного в базу), это не так уж плохо. Есть проблемы с доступом после уничтожения, которые вы должны попытаться понять. –

+0

Я не вижу необходимости в динамическом создании. Просто создайте статическую функциональную переменную, и у вас будет такая же функциональность. Преимущество состоит в том, что вы можете контролировать (до некоторой степени), когда он уничтожается, чтобы вы не получили доступ после его уничтожения. –

+0

@Martin да, вы правы, но это всего лишь пример для ленивой инициализации. –

2

Нет, и в целом объектам в C++ не предоставляются частные деструкторы. Имейте в виду, что Синглтон означает, что существует только один экземпляр, и поэтому нужно контролировать/предотвращать конструкцию, а не разрушение. Обычно singleton имеет частный конструктор, публичный деструктор, частную статическую переменную экземпляра и общедоступную статическую однопользовательскую функцию get/lazy construction, хотя на этом шаблоне есть вариации.

4

На мой взгляд, деструктор знака должен быть закрытым. В противном случае кто-то может вызвать «delete» для вашего экземпляра singleton. Я знаю, обычно никто этого не сделает. Но если мы говорим о дизайне превосходства, он должен быть устойчивым ко всем возможным предполагаемым или единичным повреждениям.

С помощью современного C++ разрешено объявлять даже частные деструкторы для статически построенных объектов. Это мой фрагмент кода для Singleton:

class Singleton 
{ 
public: 
    static Singleton& GetInstance(); 

    // Before C++ 11 
private: 
    Singleton() {} 
    ~Singleton() {} 

    Singleton(const Singleton&);   // Without implementation 
    Singleton& operator=(const Singleton&); // Without implementation 

    // Since C++ 11 
private: 
    Singleton() = default; 
    ~Singleton() = default; 

public: 
    Singleton(const Singleton&)   = delete; 
    Singleton& operator=(const Singleton&) = delete; 
}; 

Singleton& Singleton::GetInstance() 
{ 
    static Singleton instance; 
    return instance; 
} 
Смежные вопросы