Pergunta

Eu tenho um objeto Foo, e uma std :: lista de instâncias dele segurando. Meu problema é que quando eu adiciono uma nova instância para a lista, primeiro ele chama o ctor mas depois também o dtor. E então o dtor em outra instância (de acordo com o esse ponteiro).

Uma única instância é adicionado à lista, mas desde a sua dtor (juntamente com os seus pais) é chamado, o objeto não pode ser usado como esperado.

Heres algum código simplificado para ilustrar o problema:

#include <iostream>
#include <list>

class Foo
{
public:
    Foo()
    { 
        int breakpoint = 0;
    }
    ~Foo()
    { 
        int breakpoint = 0;
    }
};

int main()
{
    std::list<Foo> li;
    li.push_back(Foo());
}
Foi útil?

Solução

Quando você push_back () o objeto Foo, o objeto é Copiado para estruturas de dados internos da lista, portanto, o Dtor eo ctor de outra instância são chamados.

Todos os tipos de contêineres STL padrão em C ++ levar seus itens pelo valor, portanto, copiando-os conforme necessário. Por exemplo, sempre que um vetor precisa crescer, é possível que todos os valores do vector são copiados.

Talvez você deseja armazenar ponteiros em vez de objetos na lista. Ao fazer isso, apenas os ponteiros são copiados em vez do objeto. Mas, ao fazer isso, você tem que certificar-se de excluir os objetos, uma vez que você é feito:

for (std::list<Foo*>::iterator it = list.begin(); it != list.end(); ++it) {
    delete *it;
}
list.clear();

Como alternativa, você pode tentar usar algum tipo de classe 'ponteiro inteligente', por exemplo a partir das bibliotecas de impulso.

Outras dicas

Você está criando um Foo temporário aqui:

li.push_back( Foo() )

cópias push_back que Foo nas suas estruturas de dados internas. O Foo temporária é destruída após push_back foi executado, que irá chamar o destruidor.

Você vai precisar de um construtor de cópia adequada que aumenta alguns contagem de referência sobre os membros da classe que você não querem destruir cedo -. Ou torná-la privada para forçar-se sobre a solução ponteiro

Use esse objeto para entender:

class Foo
{
public:
    Foo(int x): m_x(x)
    { 
    std::cout << "Constructed Object: " << m_x << ")\n";
    }
    Foo(Foo const& c): m_x(c.m_x+100)
    {
    std::cout << "Copied Object: " << m_x << ")\n";
    }
    ~Foo()
    {  
    std::cout << "Destroyed Object: " << m_x << ")\n";
    }
};

O Primeiro principal

std::list<Foo*> li;
li.push_back(Foo(1));

Aqui criamos um objeto Foo temporária e push_back call (). O objeto temporário é copiado para a lista e a função retorna. Na conclusão desta instrução o objecto temporária é então destruídas (por meio do processo de destruição). Quando a lista é destruída que também irá destruir todos os obejcts que ele contém (Foo é um objeto com um destruidor de modo destruição inclui chamando o destruidor).

Assim que você deve ver somthing como este:

Constructed Object: 1
Constructed Object: 101
DestroyedObject: 1
DestroyedObject: 101

No segundo exemplo, você tem:

std::list<Foo*> li;
li.push_back(new Foo(1));

Aqui você criar dinamicamente um objeto na pilha. Em seguida, chamar o push_back (). Aqui, o ponteiro é copiado para a lista (o ponteiro não tem nenhum construtor / destruidor) assim nada acontece. A lista agora contém um ponteiro para o objeto na pilha. Quando a função retorna nada mais é feito. Quando a lista é destruído destrói (note a sutil diferença intermediários destruir e eliminar) o objeto que ele contém (um ponteiro), mas um ponteiro não tem destrutor então nada acontece qualquer você vai vazar memória.

Assim que você deve ver somthing como este:

Constructed Object: 1

O que realmente acontece aqui é que você armazenar um cópia do objeto passado na lista, porque você está enviando-o por valor em vez de por referência. Assim, o primeiro dtor que é chamado na verdade é chamado no objeto que você passar para o método push_back, mas uma nova instância tinha sido criado pelo então e agora é armazenado na lista.

Se você não quer uma cópia do Foo objeto a ser criado, armazenar ponteiros para Foo objetos na lista em vez dos próprios objetos. Claro que ao fazê-lo você terá que liberar corretamente memória na destruição da lista.

Fazendo as segurando lista ponteiros em vez de instâncias resolve o problema com o destruidor sendo chamado. Mas eu ainda quero entender por que isso acontece.

#include <iostream>
#include <list>

class Foo
{
public:
    Foo()
    { 
        int breakpoint = 0;
    }
    ~Foo()
    { 
        int breakpoint = 0;
    }
};

int main()
{
    std::list<Foo*> li;
    li.push_back(new Foo());
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top