Li em alguns artigos que ponteiros brutos quase nunca deveriam ser usados. Em vez disso, eles sempre devem ser agrupados em ponteiros inteligentes, sejam eles de escopo ou compartilhados.
No entanto, notei que estruturas como Qt, wxWidgets e bibliotecas como Boost nunca retornam nem esperam indicadores inteligentes, como se não os estivessem usando. Em vez disso, eles retornam ou esperam ponteiros brutos. Há alguma razão para isso? Devo ficar longe de indicadores inteligentes quando escrevo uma API pública e por quê?
Basta saber por que os indicadores inteligentes são recomendados quando muitos projetos importantes parecem evitá-los.
c++
api
pointers
smart-pointers
Laurent
fonte
fonte
unique_ptr
? Nenhuma. O Qt / WxWidgets é direcionado para sistemas embarcados ou em tempo real? Não, eles são destinados ao Windows / Mac / Unix em uma área de trabalho - no máximo. Ponteiros inteligentes são para programadores que desejam corrigi-lo.Respostas:
Além do fato de muitas bibliotecas terem sido escritas antes do advento dos ponteiros inteligentes padrão, o maior motivo é provavelmente a falta de uma ABI (Interface Binária de Aplicativo) C ++ padrão.
Se você estiver escrevendo uma biblioteca apenas de cabeçalho, pode passar ponteiros inteligentes e contêineres padrão para o conteúdo do seu coração. A fonte deles está disponível para sua biblioteca em tempo de compilação, portanto você depende apenas da estabilidade de suas interfaces, não de suas implementações.
Mas, devido à falta de ABI padrão, geralmente você não pode passar esses objetos com segurança através dos limites do módulo. Um GCC
shared_ptr
provavelmente é diferente de um MSVCshared_ptr
, que também pode ser diferente de um Intelshared_ptr
. Mesmo com o mesmo compilador, essas classes não têm garantia de compatibilidade binária entre versões.O ponto principal é que, se você deseja distribuir uma versão pré - construída da sua biblioteca, precisa de uma ABI padrão na qual confiar. C não possui um, mas os fornecedores de compiladores são muito bons em interoperabilidade entre bibliotecas C para uma determinada plataforma - existem padrões de fato.
A situação não é tão boa para C ++. Compiladores individuais podem lidar com a interoperação entre seus próprios binários, para que você tenha a opção de distribuir uma versão para cada compilador suportado, geralmente o GCC e o MSVC. Mas, à luz disso, a maioria das bibliotecas apenas exporta uma interface C - e isso significa ponteiros brutos.
No entanto, o código que não é de biblioteca geralmente prefere ponteiros inteligentes em vez de dados brutos.
fonte
Pode haver muitas razões. Para listar alguns deles:
Editar : O uso de ponteiros inteligentes é uma escolha totalmente do desenvolvedor. Depende de vários fatores.
Em sistemas críticos de desempenho, talvez você não queira usar ponteiros inteligentes que geram sobrecarga
O projeto que precisa de compatibilidade com versões anteriores, talvez você não queira usar os ponteiros inteligentes que possuem recursos específicos do C ++ 11
Edit2 Há uma série de várias votações negativas no período de 24 horas por causa da passagem abaixo. Não consigo entender por que a resposta foi reduzida, mesmo que abaixo seja apenas uma sugestão de complemento e não uma resposta.
No entanto, o C ++ sempre facilita a abertura das opções. :) por exemplo
E no seu código, use-o como:
Para aqueles que dizem que um ponteiro inteligente e um ponteiro bruto são diferentes, eu concordo com isso. O código acima era apenas uma idéia em que se pode escrever um código que é intercambiável apenas com a
#define
, isso não é compulsão ;Por exemplo,
T*
deve ser excluído explicitamente, mas um ponteiro inteligente não. Podemos ter um modeloDestroy()
para lidar com isso.e use-o como:
Da mesma forma, para um ponteiro bruto, podemos copiá-lo diretamente e para ponteiro inteligente, podemos usar uma operação especial.
Onde
Assign()
está como:fonte
std::auto_ptr
que faz parte do padrão há muito tempo (e observe que eu gostostd::auto_ptr
do tipo de retorno para funções que criam objetos, mesmo que seja quase inútil em qualquer outro lugar). No C ++ 11std::unique_ptr
, não há custos adicionais sobre um ponteiro simples.unique_ptr
e no desaparecimento deauto_ptr
, o código direcionado ao C ++ 03 deve ser usado posteriormente, enquanto o código direcionado ao C ++ 11 pode usar o primeiro. Ponteiros inteligentes são nãoshared_ptr
, há muitos padrão e nenhum padrão, incluindo propostas para o padrão que foram rejeitadas comomanaged_ptr
unique_ptr
incorrem no custo de tempo de execução, masunique_ptr
são de longe o mais usado. O exemplo de código que você fornece também é enganoso, porqueunique_ptr
eT*
são conceitos totalmente diferentes. O fato de você se referir a ambostype
dá a impressão de que eles podem ser trocados um pelo outro.Há dois problemas com ponteiros inteligentes (pré C ++ 11):
O ponteiro inteligente padrão , por ser gratuito, é
unique_ptr
. Infelizmente, requer a semântica de movimentação do C ++ 11, que apareceu apenas recentemente. Todos os outros ponteiros inteligentes têm um custo (shared_ptr
,intrusive_ptr
) ou têm semântica abaixo da ideal (auto_ptr
).Com o C ++ 11 ao virar da esquina, trazendo um
std::unique_ptr
, seria possível pensar que finalmente acabou ... Não estou tão otimista.Apenas alguns compiladores principais implementam a maior parte do C ++ 11 e somente em suas versões recentes. Podemos esperar que grandes bibliotecas, como QT e Boost, estejam dispostas a manter a compatibilidade com o C ++ 03 por um tempo, o que de certa forma impede a ampla adoção dos novos e brilhantes ponteiros inteligentes.
fonte
Você não deve ficar longe de ponteiros inteligentes, eles têm seu uso especialmente em aplicativos em que você precisa passar um objeto.
As bibliotecas tendem a retornar apenas um valor ou preencher um objeto. Eles geralmente não têm objetos que precisam ser usados em muitos lugares, portanto, não há necessidade de usar ponteiros inteligentes (pelo menos não na interface, eles podem usá-los internamente).
Eu poderia tomar como exemplo uma biblioteca em que estivemos trabalhando, onde, após alguns meses de desenvolvimento, percebi que só usamos ponteiros e ponteiros inteligentes em algumas classes (3-5% de todas as classes).
Passar variáveis por referência foi suficiente na maioria dos lugares, usamos ponteiros inteligentes sempre que tínhamos um objeto que poderia ser nulo e ponteiros brutos quando uma biblioteca que usamos nos forçava.
Editar (não posso comentar por causa da minha reputação): passar variáveis por referência é muito flexível: se você deseja que o objeto seja somente leitura, pode usar uma referência const (você ainda pode fazer algumas projeções desagradáveis para poder escrever o objeto ), mas você obtém o máximo de proteção possível (o mesmo acontece com os ponteiros inteligentes). Mas concordo que é muito melhor apenas retornar o objeto.
fonte
O Qt reinventou inutilmente muitas partes da biblioteca Standard, na tentativa de se tornar Java. Acredito que atualmente ele tenha seus próprios indicadores inteligentes, mas, em geral, dificilmente é um pináculo do design. Até onde sei, o wxWidgets foi projetado muito antes da escrita de ponteiros inteligentes utilizáveis.
Quanto ao Boost, espero que eles usem ponteiros inteligentes sempre que apropriado. Você pode ter que ser mais específico.
Além disso, não esqueça que existem indicadores inteligentes para reforçar a propriedade. Se a API não possui semântica de propriedade, por que usar um ponteiro inteligente?
fonte
QString
, wxWidgetswxString
, MFC tem o nome horrívelCString
. Um UTF-8 não éstd::string
bom o suficiente para 99% das tarefas da GUI?Boa pergunta. Não conheço os artigos específicos aos quais você se refere, mas li coisas semelhantes de tempos em tempos. Minha suspeita é que os autores desses artigos tendem a ter um viés contra a programação no estilo C ++. Se o gravador programar em C ++ somente quando for necessário, retornar ao Java ou assim que puder, ele realmente não compartilhará a mentalidade de C ++.
Suspeita-se que alguns ou a maioria dos mesmos escritores prefiram gerenciadores de memória coletores de lixo. Eu não, mas penso de forma diferente do que eles.
Os indicadores inteligentes são ótimos, mas precisam manter as contagens de referência. A manutenção das contagens de referência suporta custos - geralmente custos modestos, mas, no entanto - no tempo de execução. Não há nada errado em economizar esses custos usando ponteiros simples, especialmente se os ponteiros forem gerenciados por destruidores.
Uma das coisas excelentes sobre C ++ é o suporte à programação de sistemas embarcados. O uso de indicadores simples faz parte disso.
Atualização: Um comentarista observou corretamente que o novo C ++
unique_ptr
(disponível desde TR1) não conta referências. O comentarista também tem uma definição diferente de "ponteiro inteligente" do que eu tenho em mente. Ele pode estar certo sobre a definição.Atualização adicional: o tópico de comentário abaixo está iluminado. Tudo isso é leitura recomendada.
fonte
shared_ptr
mantém uma contagem de referência. Existem muitos outros tipos de ponteiros inteligentes que não mantêm uma contagem de referência. Por fim, as bibliotecas mencionadas são direcionadas a plataformas que possuem muitos recursos de sobra. Não que eu fosse o menos votado, mas tudo o que estou dizendo é que sua postagem está cheia de erros.shared_ptr
não tem sobrecarga. Ele só tem sobrecarga se você não precisar de semântica de propriedade compartilhada com segurança de thread, que é o que ela fornece.Existem também outros tipos de ponteiros inteligentes. Você pode querer um ponteiro inteligente especializado para algo como replicação de rede (que detecta se foi acessada e envia quaisquer modificações ao servidor ou algo parecido), mantém um histórico de alterações, marca o fato de que foi acessado para que possa ser investigado quando você salva dados no disco e assim por diante. Não tenho certeza se fazer isso no ponteiro é a melhor solução, mas usar os tipos de ponteiro inteligente embutidos nas bibliotecas pode resultar em pessoas bloqueadas nelas e perder a flexibilidade.
As pessoas podem ter todos os tipos de requisitos e soluções de gerenciamento de memória diferentes, além de indicadores inteligentes. Talvez eu queira gerenciar a memória pessoalmente, alocando espaço para as coisas em um pool de memória, para que seja alocado antecipadamente e não em tempo de execução (útil para jogos). Talvez eu esteja usando uma implementação de C ++ coletada por lixo (o C ++ 11 torna isso possível, embora ainda não exista). Ou talvez eu não esteja fazendo nada avançado o suficiente para me preocupar em incomodá-los, posso saber que não vou esquecer de objetos não inicializados e assim por diante. Talvez eu esteja confiante na minha capacidade de gerenciar a memória sem a muleta do ponteiro.
A integração com C também é outra questão.
Outra questão é que ponteiros inteligentes fazem parte do STL. O C ++ foi projetado para ser utilizável sem o STL.
fonte
Também depende do domínio em que você trabalha. Eu escrevo mecanismos de jogo para viver, evitamos o impulso como uma praga, em jogos a sobrecarga do impulso não é aceitável. Em nosso mecanismo principal, acabamos escrevendo nossa própria versão do stl (bem como a ea stl).
Se eu fosse escrever um aplicativo de formulários, poderia considerar o uso de ponteiros inteligentes; mas quando o gerenciamento de memória é uma segunda natureza, não ter controle granular sobre a memória torna-se silenciosamente irritante.
fonte