Pergunta

Eu escrevo um singleton c ++ no caminho a seguir:

class A {
    private:
        static A* m_pA;
        A();
        virtual ~A();

    public:
        static A* GetInstance();
        static void FreeInstance();

        void WORK1();
        void WORK2();
        void WORK3();
    }
}

A* A::GetInstance() {
    if (m_pA == NULL)
        m_pA = new A();
    return m_pA;
}

A::~A() {
    FreeInstance()  // Can I write this? are there any potential error?
}

void A::FreeInstance() {
    delete m_pA;
    m_pA = NULL;
}

Obrigado! resposta Evan Teran e sep61.myopenid.com 's é certo, e muito bom! Meu caminho é errado, eu gostaria que qualquer um escrevendo esse código pode evitar o meu erro bobo.

Meu Singleton A no meu projeto tem um vetor de ponteiro inteligente, e outro segmento também pode editar este vector, por isso, quando a aplicação está fechando, ele sempre ficar instável até eu adicionar lotes de CMutex. erro multithread + erro singleton me desperdiçado 1 dia.

// ------------------------------------------------ ----------- Um novo Singleton, você está convidado a editar se você acha que há qualquer problema no exemplo a seguir:

class A {
    private:
        static A* m_pA;
        explicit A();
        void A(const A& a);
        void A(A &a);
        const A& operator=(const A& a);
        virtual ~A();

    public:
        static A* GetInstance();
        static void FreeInstance();

        void WORK1();
        void WORK2();
        void WORK3();
    }
}

A* A::GetInstance() {
    if (m_pA == NULL){
        static A self;
        m_pA = &self;
    }
    return m_pA;
}

A::~A() {
}
Foi útil?

Solução

Você pode evitar a necessidade de excluí-lo usando um objeto estático como este:

if(m_pA == 0) {
    static A static_instance;
    m_pA = &static_instance;
}

Outras dicas

Por que todo mundo deseja retornar um singleton como um ponteiro?
Devolvê-lo como uma referência parece muito mais lógico!

Você nunca deve ser capaz de libertar um singleton manualmente. Como você sabe que está mantendo uma referência para o singleton? Se você não sabe (ou não pode garantir) ninguém tem uma referência (no seu caso através de um ponteiro), então você não tem nenhum negócio que livra o objeto.

Use a estática em um método da função.
Isso garante que ela é criada e destruída apenas uma vez. Ela também lhe dá a inicialização lenta gratuitamente.

class S
{
    public:
        static S& getInstance()
        {
            static S    instance;
            return instance;
        }
    private:
        S() {}
        S(S const&);              // Don't Implement.
        void operator=(S const&); // Don't implement
 };

Note que você também precisa fazer o construtor privado. Também certifique-se que você substituir o construtor de cópia padrão e operador de atribuição de modo que você não pode fazer uma cópia do Singleton (caso contrário, não seria um singleton).

Leia também:

Para se certificar de que você está usando um singleton pelas razões corretas.

Apesar de tecnicamente não o segmento de seguros no caso geral ver:
Qual é o tempo de vida de uma variável estática em uma C ++ função?

GCC tem um remendo explícita para compensar esta:
http://gcc.gnu.org/ml/gcc-patches /2004-09/msg00265.html

Um singleton em C ++ pode ser escrito desta forma:

static A* A::GetInstance() {
    static A sin;
    return &sin;
}

Apenas não se esqueça de fazer operadores o construtor de cópia e de atribuição privado.

Eu não acho que haja qualquer razão para escrever essa linha não. Seu método de destruidor não é estática e sua instância singleton não vai ser destruída dessa maneira. Eu não acho que o destruidor é necessário, se você precisa limpar o uso objeto o método estático que você criou alread, FreeInstance ().

Além disso, você cria seus singletons em aproximadamente da mesma forma que eu crio meu.

Depois de um período de entusiasmo selvagem para singletons Meyers-estilo (usando objetos estáticos locais como em algumas das respostas anteriores), eu tenho completamente farto dos problemas de gestão da vida em aplicações complicadas.

Eu tendem a achar que você acaba fazendo referência o método 'Instância' deliberadamente cedo na inicialização do aplicativo, para se certificar de que eles estão criados quando você quer, e, em seguida, jogando todos os tipos de jogos com a lágrima-down por causa da imprevisível (ou pelo menos muito complicado e um pouco oculto) ordem em que as coisas são destruídas.

YMMV, naturalmente, e isso depende um pouco sobre a natureza do singleton em si, mas uma grande parte do waffle sobre singletons inteligentes (e a rosca / problemas de bloqueio que cercam a esperteza) é superestimada IMO.

Se você ler "Projeto C ++ moderna" você vai perceber que um projeto singleton poderia ser muito mais complexo do que o retorno uma variável estática.

Esta implementação é bom, desde que você pode responder a estas perguntas:

  1. Você sabe quando o objeto será criado (se você usar um objeto estático em vez de novo? Você tem um main ()?)

  2. se você Singleton tem nenhuma dependência que podem não estar pronto no momento em que é criado? Se você usar um objeto estático em vez de novo, o que as bibliotecas foram inicializados por esta altura? O que o seu objeto faz no construtor que pode obrigá-los?

  3. quando será eliminada?

Usando new () é mais seguro porque você controla onde e quando o objeto será criado e excluído. Mas então você precisa excluí-lo explicitamente e provavelmente ninguém no sistema sabe quando fazê-lo. Você pode usar atexit () para isso, se faz sentido.

Usando um objeto estático no meio de métodos que fazem realmente não sei quando será criado ou excluído. Você poderia também usar um objeto estático global em um espaço de nomes e evitar getInstance () em tudo -. Isso não acrescenta muito

Se você não usar threads, então você está em apuros. É virtualmente impossível criar utilizável fio Singleton seguro em C ++ devido a:

  1. bloqueio permanente em getInstance é muito pesado - um interruptor contexto completo em cada getInstance ()
  2. bloqueio duplo verificado falhar devido a otimizações do compilador e cache de modelo de memória / fraco, é muito complicado de implementar, e impossível de teste. Eu não iria tentar fazê-lo em um sistema real, a menos que você intimamente sabe sua arquitetura e quer que ele seja não portátil

Estes podem ser Googled facilmente, mas aqui está um bom link no modelo de memória fraca: http://ridiculousfish.com/blog/archives/2007/02/17/barrier .

Uma solução seria a utilização de bloqueio, mas exigem que os usuários de armazenar em cache o ponteiro que recebem de getInctance () e estar preparado para getInstance () para ser pesado.

Outra solução seria a de permitir que os usuários alça de segurança do thread si mesmos.

No entanto, outra solução seria a utilização de uma função com simples bloqueio e substituí-lo com outra função sem bloqueio e verificação uma vez que o novo () foi chamado. Isso funciona, mas a implementação completa é complicado.

Não é uma biblioteca grande C ++, ACE, com base em padrões. Há uma grande quantidade de documentação sobre diferentes tipos de padrões Então olhe para o seu trabalho: http://www.cs.wustl.edu/~schmidt/ACE.html

//! @file singleton.h
//!
//! @brief Variadic template to make a singleton out of an ordinary type.
//!
//! This template makes a singleton out of a type without a default
//! constructor.

#ifndef SINGLETON_H
#define SINGLETON_H

#include <stdexcept>

template <typename C, typename ...Args>
class singleton
{
private:
  singleton() = default;
  static C* m_instance;

public:
  singleton(const singleton&) = delete;
  singleton& operator=(const singleton&) = delete;
  singleton(singleton&&) = delete;
  singleton& operator=(singleton&&) = delete;

  ~singleton()
  {
    delete m_instance;
    m_instance = nullptr;
  }

  static C& create(Args...args)
  {
    if (m_instance != nullptr)
      {
    delete m_instance;
    m_instance = nullptr;
      }
    m_instance = new C(args...);
    return *m_instance;
  }

  static C& instance()
  {
    if (m_instance == nullptr)
      throw std::logic_error(
        "singleton<>::create(...) must precede singleton<>::instance()");
    return *m_instance;
  }
};

template <typename C, typename ...Args>
C* singleton<C, Args...>::m_instance = nullptr;

#endif // SINGLETON_H
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top