Что не так с этой реализацией Singleton? - PullRequest
5 голосов
/ 12 июня 2011

Идея состоит в том, чтобы удалить Singleton в C ++ после завершения программы.Мы изучили этот метод реализации в классе:

class Singleton
{

private:
    static Singleton* the_singleton;

protected:
    Singleton()
    {
        static Keeper keeper(this);
        /*CONSTRUCTION CODE*/
    }
    virtual ~Singleton()
    {
        /*DESTRUCTION CODE*/
    }

public:
    class Keeper
    {

    private:
        Singleton* m_logger;

    public:
        Keeper(Singleton* logger):m_logger(logger){}

        ~Keeper()
        {
            delete m_logger;
        }
    };
    friend class Singleton::Keeper;

    static Singleton* GetInstance();
    {
        if (!the_singleton)
            the_singleton = new Singleton();
        return the_singleton;
    }
};

Singleton* Singleton::the_singleton = NULL;

Идея состоит в том, что в первый раз, когда создается Singleton, статический объект Keeper будет создан в C'or Singleton, и как только программа завершитсятот Keeper будет уничтожен и, в свою очередь, уничтожит экземпляр Singleton, на который он указывает.

Теперь этот метод мне кажется довольно громоздким, поэтому я предложил отказаться от класса Keeper и сделать экземпляр Singleton aстатический объект метода getInstance:

<!-- language: c++ -->

class Singleton
{

protected:
    Singleton()
    {
        /*CONSTRUCTION CODE*/
    }

    ~Singleton()
    {
        /*DESTRUCTION CODE*/
    }

public:
    static Singleton &getInstance()
    {
        static Singleton instance;
        return instance;
    }

    /*OBJECT FUNCTIONALITY*/
};

Таким образом, Singleton создается при первом вызове метода getInstance и уничтожается после завершения программы.Нет необходимости в этом классе хранителя.

Я проверил его, и он работал просто отлично - Синглтон был создан и уничтожен в нужных местах.Тем не менее, мой ТА сказал, что эта схема неверна, хотя он не мог вспомнить, что именно было с ней.Поэтому я надеюсь, что кто-то здесь уже сталкивался с этой реализацией и может сказать мне, что с ней не так.

Ответы [ 3 ]

9 голосов
/ 12 июня 2011

Это неправильно, но ваши модификации не привели к проблемам - они были там все время.

В настоящее время нет никакого применения свойства singleton.Конструктор должен быть закрытым, не защищенным, чтобы гарантировать, что дополнительные экземпляры не будут созданы.


Кроме того, исходный код полностью непригоден для многопоточного сценария. Ваш будет работать, начиная с C ++ 0x .


Если бы объект-хранитель TA сбросил глобальный указатель обратно на NULL, его реализация была бы в состоянии (в однопоточной среде)) воссоздать синглтон при необходимости во время очистки программы.Прочитайте Шаблон Singleton в C ++ .Но это все равно будет новый экземпляр синглтона, который является почти таким же неожиданным, как использование синглтона после того, как был вызван его деструктор.

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


Вы, конечно, будете отмечены за использование улучшенной версии, это просто показывает, что целькласс не для того, чтобы научить вас C ++, но заблуждения ТА относительно C ++.

6 голосов
/ 12 июня 2011

Нет проблем с этим вообще.ИМХО, вещь "Хранитель" - это безумие для этого приложения.

В некоторых случаях это может быть оправдано.Например, если Singleton должен принимать аргументы конструктора, его статическое распределение может оказаться невозможным.Или, если его конструктор может потерпеть неудачу, более простой подход не позволит вам восстановить или повторить попытку.Поэтому в некоторых обстоятельствах может потребоваться сделать что-то более сложное.Однако во многих случаях это не нужно.

0 голосов
/ 12 июня 2011

"У вас хотя бы область памяти продолжает действовать, даже если срок службы объекта закончился "

Это правда, но не должно много значить для выполнения программы - деструктор может оставить область памяти в состоянии, в котором его использование все равно будет неудачным - например. освобождение внутреннего буфера. Вы НИКОГДА не должны использовать объект после вызова его деструктора - если вы хотите использовать свой синглтон из деструкторов других статических / глобальных объектов, то у вас нет никакой гарантии порядка, в котором эти деструкторы будут вызываться.

Если вы используете статический объект, и какой-то другой деструктор попытается использовать его после того, как он будет уничтожен, невозможно будет проверить, существует ли еще синглтон. Если вы используете объект Keeper, который установит указатель на NULL, то в других деструкторах вы можете по крайней мере проверить наличие указателя NULL и решить вообще не использовать синглтон. Таким образом, хотя вы можете потерпеть неудачу в том, что намереваетесь сделать, по крайней мере вы не получите загадочную «ошибку сегментации» или «нарушение доступа», и программа избежит аварийного завершения.

EDIT: Вам нужно помнить, чтобы модифицировать вашу функцию доступа, чтобы не создавать объект еще раз, после того как ваш хранитель установит для этого поля значение NULL - возможно, дополнительный статический bool, который сообщает, что объект был уже освобожден?

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