Pergunta

Os objetos devem Singleton que não usam contadores instância / de referência ser considerados vazamentos de memória em C ++?

Sem um contador que apela a exclusão explícita da instância singleton quando a contagem é zero, como é que o objeto ficar excluído? É limpos pelo sistema operacional quando o aplicativo é encerrado? E se essa Singleton tinha memória alocada na pilha?

Em poucas palavras, eu tenho que chamar o destrutor para uma Singelton ou posso contar com ele se limpou quando os termina de aplicação?

Foi útil?

Solução

Você pode contar com ele sendo limpos pelo sistema operacional.

Dito isto, se você estiver em uma linguagem lixo coletado com finalizadores ao invés de destruidores você pode querer ter um procedimento de desligamento que podem limpa desligamento seus singletons diretamente para que eles possam liberar quaisquer recursos críticos no caso de haver estão usando recursos do sistema que não serão corretamente limpo por apenas terminando a aplicação. Isso ocorre porque finalizadores executado em uma espécie de base 'melhor esforço' na maioria dos idiomas. Por outro lado, há muito poucos recursos que necessitam deste tipo de confiabilidade. identificadores de arquivo, memória, etc. tudo de volta ir para o sistema operacional limpa independentemente.

Se você estiver usando um singleton que é preguiçosamente alocado (ou seja, com um triplo-check bloqueio idioma) em uma linguagem como C ++ com destruidores real ao invés de finalizadores, então você não pode confiar em seu destruidor sendo chamado durante o encerramento do programa. Se você estiver usando uma instância estática única, em seguida, o destruidor será executado após principais concluída em algum ponto.

De qualquer maneira, quando termina o processo, todos os retornos de memória para o sistema operacional.

Outras dicas

Como tantas vezes, "depende". Em qualquer sistema operacional digna desse nome, quando seus sai do processo, toda a memória e outros recursos utilizados localmente dentro do processo será lançado. Você simplesmente não precisa se preocupar com isso.

No entanto, se o seu singleton está alocando recursos com uma vida fora é próprio processo (talvez um arquivo, um mutex nomeado, ou algo similar), então você precisa considerar a limpeza apropriada.

RAII irá ajudá-lo aqui. Se você tem um cenário como este:

class Tempfile
{
Tempfile() {}; // creates a temporary file 
virtual ~Tempfile(); // close AND DELETE the temporary file 
};

Tempfile &singleton()
{
  static Tempfile t;
  return t;
}

... então você pode ter certeza de que o seu arquivo temporário será fechada e excluídos no entanto os seus sai do aplicativo. No entanto, este não é thread-safe e a ordem de exclusão de objeto pode não ser o que você espera ou necessita.

No entanto, se o seu singleton é implementado como este

Tempfile &singleton()
{
  static Tempfile *t = NULL;
  if (t == NULL)
    t = new Tempfile(); 
  return *t;
}

... então você tem uma situação diferente. A memória usada pelo seu tempfile vai ser recuperado, mas o arquivo não será excluído porque o destruidor não será invocado.

Você deve explicitamente limpar todos os seus objetos. Nunca contar com o OS para limpar para você.

Onde eu costumo usar um singleton é controlar encapsulate de algo como um arquivo, recursos de hardware, etc. Se não o fizer corretamente limpa que connection- posso recursos do sistema facilmente vazamento. A próxima vez que o aplicativo é executado, ele pode falhar se o recurso ainda está bloqueado pela operação anterior. Outro problema pode ser que qualquer finalization- como escrever um buffer para disk pode não ocorrer se ele ainda existe em um buffer de propriedade de uma instância singleton.

Este não é um vazamento de memória issue- a questão é mais que você pode estar vazando recursos como outros que a memória que não pode ser tão facilmente recuperados.

Cada linguagem e ambiente será diferente, embora eu concordo com @ Aaron Fisher que um singleton tende a existir para a duração do processo.

No exemplo de C ++, usando uma linguagem Singleton típico:

Singleton &get_singleton()
{
   static Singleton singleton;
   return singleton;
}

a instância Singleton será construída a primeira vez que a função é chamada, ea mesma instância vai tê-lo de destruidor chamado durante a fase mundial destructor estática no desligamento do programa.

Como você está criando o objeto?

Se você estiver usando uma variável global ou variável estática, o destruidor será chamado, assumindo o programa termina normalmente.

Por exemplo, o programa

#include <iostream>

class Test
{
    const char *msg;

public:

    Test(const char *msg)
    : msg(msg)
    {}

    ~Test()
    {
        std::cout << "In destructor: " << msg << std::endl;
    }
};

Test globalTest("GlobalTest");

int main(int, char *argv[])
{
    static Test staticTest("StaticTest");

    return 0;
}

Imprime

In destructor: StaticTest 
In destructor: GlobalTest

Qualquer tipo de alocação, exceto aqueles em memórias compartilhadas, são automaticamente limpos pelo sistema operacional quando os termina processo. Portanto, você não deve ter que chamar explicitamente o destrutor Singleton. Em outras palavras nenhum vazamento ...

Além disso, uma implementação típica singleton como Singleton os Meyers' não só é o segmento de seguros durante a inicialização na primeira chamada, mas também garantida a graciosa terminar quando sai do aplicativo (o destruidor é invocado).

De qualquer forma, se o pedido é enviado um sinal de UNIX (ie: SIGTERM ou SIGHUP ) o comportamento padrão é para encerrar o processo sem chamar os destruidores de objetos estáticos alocados ( únicos). Para superar esse problema para estes sinais, é possível dispor de uma saída chamar manipulador, ou saída dispor ser tal manipulador - signal(SIGTERM,exit);

É de folclore para alocações de memória globais livres explicitamente antes dos termina aplicações. Suponho que a maioria de nós fazê-lo fora de hábito e porque sentimos que é uma espécie de mal a "esquecer" sobre uma estrutura. No mundo do C é uma lei de simetria que qualquer afectação deve ter um lugar deallocation. programadores C ++ pensar de forma diferente se eles sabem ea prática RAII.

Nos bons velhos tempos de exemplo AmigaOS havia vazamentos de memória real. Quando você se esqueceu de desalocar memória, nunca se tornaria acessível novamente até que o sistema foi reiniciado.

Eu não sei de qualquer sistema operacional de desktop que se preze estes dias que permitiriam vazamentos de memória a rastejar para fora do espaço de endereço virtual de um aplicativo. Sua milhagem pode variar em dispositivos embarcados quando não há extensa contabilidade memória.

Depende da sua definição de um vazamento. aumento de memória Unbound é um vazamento no meu livro, um singleton não é desacoplado. Se você não fornecer contagem de referência, você mantém intencionalmente a instância vivo. Não um acidente, não um vazamento.

destruidor do seu invólucro de singleton deve excluir a instância, não é automático. Se ele apenas aloca memória e sem recursos do sistema operacional, não há nenhum ponto.

A Singleton seria uma instância do seu objeto. É por isso que ele não necessita de um contador. Se ele vai existir para a duração da sua aplicação, em seguida, o destruidor padrão vai ficar bem. A memória será, em qualquer caso, recuperada pelo sistema operacional quando o processo termina.

Em linguagens como C ++ que não têm coleta de lixo é a melhor prática para limpar antes da terminação. Você pode fazer isso com uma classe amigo destruidor.

class Singleton{
...
   friend class Singleton_Cleanup;
};
class Singleton_Cleanup{
public:
    ~Singleton_Cleanup(){
         delete Singleton::ptr;
     }
};

Criar a classe-se limpo ao iniciar o programa e, em seguida, ao sair do destrutor será chamado a limpeza do Singleton. Isto pode ser mais detalhado do que deixá-lo ir para o sistema operacional, mas ele segue princípios RAII e, dependendo dos recursos alocados em seu objeto singleton pode ser necessário.

Qualquer memória heap alocada pelo seu processo e não libertou (suprimido) será recuperada pelo sistema operacional. Se você estiver usando a implementação mais comum do Singleton, que utiliza variáveis ??estáticas, isso seria limpado após a rescisão do seu aplicativo também.

* Isto não significa que você deve ir ao redor nova-ing ponteiros e nunca limpá-los embora.

Eu corri para uma questão como esta e eu acho que isso deve funcionar mesmo se as principais saídas de rosca primeiro e leva os objetos estáticos com ele. Em vez disso:

Singleton &get_singleton() {
   static Singleton singleton;
   return singleton;
}

Estou pensando

Singleton &get_singleton() {
   static std::shared_ptr<Singleton> singleton = std::make_shared<Singleton>();
   static thread_local std::shared_ptr<Singleton> local = singleton;
   return *local;
}

Assim, quando os principais saídas de rosca e leva singleton com ele, cada thread ainda tem o seu próprio local shared_ptr que mantém o Singleton vivo.

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