Projetando um novo sistema a partir do zero. Vou usar o STL para armazenar listas e mapas de certos objetos de vida longa.
Pergunta: Devo garantir que meus objetos tenham construtores de cópias e armazenar cópias de objetos em meus contêineres STL, ou é geralmente melhor gerenciar a vida e o escopo sozinho e apenas armazenar os ponteiros para esses objetos nos contêineres STL?
Sei que isso é um pouco curto nos detalhes, mas estou procurando a melhor resposta "teórica", se existir, pois sei que essas duas soluções são possíveis.
Duas desvantagens muito óbvias de brincar com ponteiros: 1) Devo gerenciar a alocação / desalocação desses objetos em um escopo além do STL. 2) Não consigo criar um objeto temporário na pilha e adicioná-lo aos meus contêineres.
Falta mais alguma coisa?
Respostas:
Desde que as pessoas estão compartilhando a eficácia do uso de ponteiros.
Se você estiver pensando em usar um std :: vector e se houver poucas atualizações e você repetir sua coleção, é um objeto de armazenamento de tipo não polimórfico, "cópias" serão mais eficazes, pois você obterá uma melhor localidade de referência.
Otoh, se as atualizações forem comuns, o armazenamento de ponteiros economizará os custos de cópia / realocação.
fonte
Isso realmente depende da sua situação.
Se seus objetos são pequenos e fazer uma cópia do objeto é leve, então armazenar os dados em um contêiner stl é simples e fácil de gerenciar, na minha opinião, porque você não precisa se preocupar com o gerenciamento da vida útil.
Se seus objetos são grandes e ter um construtor padrão não faz sentido, ou cópias de objetos são caras, o armazenamento com ponteiros é provavelmente o caminho a percorrer.
Se você decidir usar ponteiros para objetos, dê uma olhada na Biblioteca de Contêineres de Boost Pointer . Essa biblioteca de reforço agrupa todos os contêineres STL para uso com objetos alocados dinamicamente.
Cada contêiner de ponteiro (por exemplo, ptr_vector) assume a propriedade de um objeto quando ele é adicionado ao contêiner e gerencia a vida útil desses objetos para você. Você também acessa todos os elementos em um contêiner ptr_ por referência. Isso permite que você faça coisas como
Essas classes envolvem os contêineres STL e funcionam com todos os algoritmos STL, o que é realmente útil.
Também existem facilidades para transferir a propriedade de um ponteiro no contêiner para o chamador (através da função de liberação na maioria dos contêineres).
fonte
Se você estiver armazenando objetos polimórficos, sempre precisará usar uma coleção de ponteiros de classe base.
Ou seja, se você planeja armazenar diferentes tipos derivados em sua coleção, deve armazenar ponteiros ou ser comido pelo deamon fatiado.
fonte
Desculpe pular três anos após o evento, mas uma nota de advertência aqui ...
No meu último grande projeto, minha estrutura central de dados era um conjunto de objetos bastante diretos. Cerca de um ano após o projeto, à medida que os requisitos evoluíram, percebi que o objeto realmente precisava ser polimórfico. Foram necessárias algumas semanas de cirurgia cerebral difícil e desagradável para corrigir a estrutura de dados para ser um conjunto de indicadores de classe base e para lidar com todos os danos colaterais no armazenamento de objetos, na projeção e assim por diante. Levei alguns meses para me convencer de que o novo código estava funcionando. Aliás, isso me fez pensar muito sobre o quão bem projetado é o modelo de objeto do C ++.
No meu grande projeto atual, minha estrutura central de dados é um conjunto de objetos bastante diretos. Cerca de um ano depois do projeto (o que acontece hoje), percebi que o objeto realmente precisa ser polimórfico. De volta à rede, localizei este segmento e localizei o link de Nick para a biblioteca de contêineres de ponteiro Boost. Isso é exatamente o que eu tive que escrever da última vez para consertar tudo, então vou tentar desta vez.
A moral, para mim, de qualquer maneira: se suas especificações não forem 100% moldadas em pedra, procure dicas e você poderá economizar muito trabalho mais tarde.
fonte
Por que não obter o melhor dos dois mundos: faça um contêiner de ponteiros inteligentes (como
boost::shared_ptr
oustd::shared_ptr
). Você não precisa gerenciar a memória e não precisa lidar com grandes operações de cópia.fonte
Geralmente, armazenar os objetos diretamente no contêiner STL é melhor, pois é mais simples, mais eficiente e mais fácil de usar o objeto.
Se o seu objeto tiver uma sintaxe não copiável ou for um tipo de base abstrato, será necessário armazenar ponteiros (o mais fácil é usar o shared_ptr)
fonte
Você parece ter uma boa noção da diferença. Se os objetos são pequenos e fáceis de copiar, então guarde-os.
Caso contrário, eu pensaria em armazenar ponteiros inteligentes (não auto_ptr, um ref que conta ponteiros inteligentes) para aqueles que você aloca no heap. Obviamente, se você optar por ponteiros inteligentes, não poderá armazenar objetos alocados da pilha temporária (como você disse).
@ Torbjörn faz um bom argumento sobre fatiar.
fonte
one
paraanother
liberará a referênciaone
e será alteradaone
.O uso de ponteiros será mais eficiente, pois os contêineres apenas copiarão os ponteiros ao invés de objetos completos.
Há algumas informações úteis aqui sobre contêineres STL e ponteiros inteligentes:
Por que é errado usar std :: auto_ptr <> com contêineres padrão?
fonte
Se os objetos tiverem que ser referidos em outra parte do código, armazene em um vetor de boost :: shared_ptr. Isso garante que os ponteiros para o objeto permaneçam válidos se você redimensionar o vetor.
Ou seja:
Se ninguém mais armazenar ponteiros para os objetos, ou a lista não aumentar e diminuir, basta armazenar como objetos antigos simples:
fonte
Esta pergunta está me incomodando há um tempo.
Eu gosto de armazenar ponteiros, mas tenho alguns requisitos adicionais (wrappers lua SWIG) que podem não se aplicar a você.
O ponto mais importante neste post é testar você mesmo , usando seus objetos
Fiz isso hoje para testar a velocidade de chamar uma função de membro em uma coleção de 10 milhões de objetos, 500 vezes.
A função atualiza x e y com base em xdir e ydir (todas as variáveis de membro flutuantes).
Eu usei um std :: list para armazenar os dois tipos de objetos e descobri que armazenar o objeto na lista é um pouco mais rápido do que usar um ponteiro. Por outro lado, o desempenho foi muito próximo, portanto, tudo se resume a como eles serão usados no seu aplicativo.
Para referência, com -O3 no meu hardware, os ponteiros levaram 41 segundos para serem concluídos e os objetos brutos levaram 30 segundos para serem concluídos.
fonte