Piores práticas em C ++, erros comuns [fechado]


35

Depois de ler esse famoso discurso de Linus Torvalds , perguntei-me quais são as armadilhas para os programadores em C ++. Não estou explicitamente me referindo a erros de digitação ou fluxo incorreto de programa, conforme tratado nesta pergunta e suas respostas , mas a erros de mais alto nível que não são detectados pelo compilador e não resultam em erros óbvios na primeira execução, erros de design completos, coisas improváveis ​​em C, mas que provavelmente serão feitas em C ++ por recém-chegados que não entendem todas as implicações de seu código.

Também sou bem-vindo a respostas que apontam para uma enorme queda no desempenho, onde normalmente não seria esperado. Um exemplo do que um dos meus professores me contou uma vez sobre um gerador de analisador LR (1) que escrevi:

Você usou muitas instâncias de herança e virtualidade desnecessárias. A herança torna um design muito mais complicado (e ineficiente por causa do subsistema RTTI (inércia do tipo de tempo de execução)) e, portanto, deve ser usado apenas onde faz sentido, por exemplo, para as ações na tabela de análise. Como você faz uso intensivo de modelos, praticamente não precisa de herança. "


6
Alguns dos erros mais desagradáveis ​​que você pode cometer em C / C ++ são principalmente por causa da herança C ... leia comportamento indefinido, gerenciamento manual de memória, etc. Além disso, o conselho do professor parece falso / errado (para mim, quem não é um especialista em C ++) - a instanciação do modelo deve gerar uma classe normal com vtable para virtualfunções, certo?

8
Ou você está se lembrando mal do que o seu professor disse, ou ele não tinha idéia do que estava falando. As classes derivadas geralmente não precisam usar RTTI (reflexão AKA) para pesquisar as coisas. Se eles estiverem usando métodos virtuais, o código pode precisar fazer uma pesquisa em vtable para o envio, mas isso se traduz em uma única instrução ASM em muitos processadores. Devido a problemas de armazenamento em cache, as coisas podem ficar mais lentas, mas é improvável que você note a sobrecarga nos casos de uso mais exigentes. Existem muitas boas razões para evitar C ++, mas as pesquisas de vtable não são uma delas.
Mason Wheeler

5
@FelixDombek: Declarada de forma tão generosa e aplicada em todos os aspectos, essa citação de seu professor mostra uma enorme quantidade de ignorância. Quando seu design precisa de algum tipo de polimorfismo de tempo de execução, o uso de funções virtuais geralmente é a melhor opção; quando você não precisar, não use: você não precisa que todos os métodos sejam virtuais apenas porque você usa classes derivadas, por exemplo.
Fred Nurk

5
@Mason Wheeler: O RTTI contém informações sobre o tipo, o suficiente para determinar se um dynamic_castdeve ser bem-sucedido ou não, e poucas outras coisas, mas a reflexão abrange muito mais, incluindo a possibilidade de recuperar informações sobre atributos ou funções de membros, o que não é presente em C ++.
David Rodríguez - dribeas 7/02/11

5
O comentário do professor é um tanto enganador, pois a herança e as funções virtuais não são um grande problema de desempenho. O conselho para usar a herança com moderação é bom, mas é mais um problema da estrutura do programa do que eficiência. A herança, principalmente com membros protegidos, é o mais próximo possível do acoplamento e, se você não precisar, não deve usá-lo.
David Thornley

Respostas:


69

Torvalds está falando demais aqui.


OK, por que ele está falando sério:

Primeiro de tudo, seu discurso retórico não é realmente nada, mas discurso retórico. Há muito pouco conteúdo real aqui. A única razão pela qual é realmente famoso ou até levemente respeitado é porque foi feita pelo Deus Linux. Seu principal argumento é que C ++ é uma porcaria e ele gosta de irritar as pessoas em C ++. É claro que não há razão alguma para responder a isso e qualquer um que considere um argumento razoável está além da conversa de qualquer maneira.

Quanto ao que pode ser considerado como seus pontos mais objetivos:

  • STL e Boost são uma porcaria absoluta <- tanto faz. Você é um idiota.
  • STL e Boost causam quantidades infinitas de dor <- ridículas. Obviamente, ele está exagerando de propósito, mas qual é a verdadeira afirmação dele aqui? Eu não sei. Há algumas questões mais do que trivialmente difíceis de entender quando você causa vômito no compilador no Spirit ou algo assim, mas não é mais ou menos difícil de descobrir do que depurar o UB causado pelo uso indevido de construções C como void *.
  • Modelos abstratos incentivados por C ++ são ineficientes. <- Como o que? Ele nunca se expande, nunca fornece exemplos do que ele quer dizer, ele apenas diz isso. BFD. Como não sei dizer ao que ele está se referindo, não faz sentido tentar "refutar" a afirmação. É um mantra comum dos fanáticos do C, mas que não o torna mais compreensível ou inteligível.
  • O uso correto do C ++ significa que você se limita aos aspectos do C. <- Na verdade, o código WORSE C ++ lá fora faz isso, então eu ainda não sei do que ele está falando.

Basicamente, Torvalds está falando maluco. Não há argumento inteligível sobre nada. Esperar uma refutação séria de tal absurdo é simplesmente bobagem. Estou me dizendo para "expandir" em uma refutação de algo que eu deveria expandir se fosse onde eu o dissesse. Se você realmente, honestamente, olhar para o que Torvalds disse, verá que ele não disse nada.

Só porque Deus diz que não significa que faça algum sentido ou deva ser levado mais a sério do que se algum bozo aleatório o dissesse. Verdade seja dita, Deus é apenas mais um bozo aleatório.


Respondendo à pergunta real:

Provavelmente, a pior e mais comum prática ruim de C ++ é tratá-la como C. O uso contínuo de funções da API C como printf, gets (também considerado ruim em C), strtok, etc ... não apenas falha em aproveitar a energia fornecida pelo sistema mais rígido, eles inevitavelmente levam a complicações adicionais ao tentar interagir com o código C ++ "real". Então, basicamente, faça exatamente o oposto do que Torvalds está aconselhando.

Aprenda a alavancar o STL e o Boost para obter mais detecção de erros no tempo de compilação e facilitar sua vida de outras maneiras gerais (o tokenizer de impulso, por exemplo, é seguro para o tipo E uma interface melhor). É verdade que você precisará aprender a ler erros de modelo, o que é assustador no começo, mas (na minha experiência de qualquer maneira) é francamente muito mais fácil do que tentar depurar algo que gera comportamento indefinido durante o tempo de execução, que a API C faz bastante fácil de fazer.

Para não dizer que C não é tão bom. É claro que eu gosto mais de C ++. Programadores C como C melhor. Existem trocas e gostos subjetivos em jogo. Também há muita desinformação e FUD flutuando. Eu diria que há mais FUD e desinformação flutuando sobre o C ++, mas sou tendenciosa a esse respeito. Por exemplo, os problemas de "inchaço" e "desempenho" que o C ++ supostamente não tem, na verdade, são problemas importantes na maioria das vezes e certamente são exagerados nas proporções da realidade.

Quanto aos problemas aos quais seu professor está se referindo, eles não são exclusivos do C ++. No OOP (e na programação genérica), você deseja preferir a composição do que a herança. A herança é o relacionamento de acoplamento mais forte possível que existe em todos os idiomas OO. C ++ adiciona mais um que é mais forte, a amizade. A herança polimórfica deve ser usada para representar abstrações e relacionamentos "é-a", nunca deve ser usada para reutilização. Esse é o segundo maior erro que você pode cometer em C ++, e é bem grande, mas está longe de ser exclusivo da linguagem. Você também pode criar relacionamentos de herança excessivamente complexos em C # ou Java, e eles terão exatamente os mesmos problemas.


11
Irônico, até bem depois de 2007, o git executava apenas versões portáteis do Linux. Bem, qualquer sistema que fosse unix. Por outro lado, dadas as circunstâncias que levaram à criação do git, certamente não estou segurando isso contra ele.
Chris K

9
Linus tem dificuldade em encontrar bons programadores de C ++ que queiram trabalhar para ele. Imagino por que? Acho que esse é apenas um problema do tipo ovo e galinha.
Bo Persson

19

Eu sempre pensei que os perigos do C ++ eram altamente exagerados por inexperientes, C com programadores de classes.

Sim, o C ++ é mais difícil de entender do que algo como Java, mas se você programar usando técnicas modernas, é muito fácil escrever programas robustos. Eu honestamente não têm que muito mais difícil de um tempo de programação em C ++ do que eu em linguagens como Java, e muitas vezes eu encontro-me faltando certas abstrações C ++ como modelos e RAII quando eu projeto em outros idiomas.

Dito isto, mesmo depois de anos de programação em C ++, de vez em quando cometerei um erro realmente estúpido que não seria possível em uma linguagem de nível superior. Uma armadilha comum no C ++ é ignorar a vida útil do objeto: em Java e C #, geralmente você não precisa se preocupar com a vida útil do objeto *, porque todos os objetos existem na pilha e são gerenciados por um coletor de lixo mágico.

Agora, no C ++ moderno, geralmente você também não precisa se preocupar muito com a vida útil do objeto. Você tem destruidores e ponteiros inteligentes que gerenciam a vida útil dos objetos para você. 99% do tempo, isso funciona maravilhosamente. Mas, de vez em quando, você é ferrado por um ponteiro oscilante (ou referência). Por exemplo, recentemente, eu tive um objeto (vamos chamá-lo Foo) que continha uma variável de referência interna para outro objeto (vamos chamá-lo Bar). Em um ponto, eu estupidamente organizei as coisas para que Barestivessem fora de escopo antes Foo, mas Fooo destruidor acabou chamando uma função de membro de Bar. Escusado será dizer que as coisas não saíram bem.

Agora, não posso culpar C ++ por isso. Era o meu próprio design ruim, mas a questão é que esse tipo de coisa não aconteceria em uma linguagem gerenciada de nível superior. Mesmo com indicadores inteligentes e similares, às vezes você ainda precisa ter consciência do tempo de vida do objeto.


* Se o recurso que está sendo gerenciado é memória, é isso.


8
Nunca realmente precisa se preocupar com a vida útil do objeto em Java e C #? O GC deles cuida da memória, mas isso é apenas uma pequena parte do RAII para mim; observe as várias interfaces "descartáveis" que essas linguagens possuem, por exemplo.
Fred Nurk

Ter que se preocupar com a vida útil do objeto seria raro em Java, exceto pelo design inconveniente de sua biblioteca de E / S.
dan04

Seu problema de referência pendente é algo que estou interessado em tentar resolver. Comecei uma discussão no meu blog sobre a direção que estou tomando para resolvê-lo (promessas do ponteiro). Basicamente, acho que a linguagem poderia usar mais alguns indicadores inteligentes. Participe dessa discussão se estiver interessado. Ninguém mais foi tão ... mas se é algo que você gostaria de ver resolvido ... Na verdade, eu me deparo com a questão mais de 10% do tempo.
Edward Strange

13

A diferença no código geralmente está mais relacionada ao programador do que ao idioma. Em particular, um bom programador de C ++ e um programador de C virão para soluções igualmente boas (mesmo que diferentes). Agora, C é uma linguagem mais simples (como uma linguagem) e isso significa que há menos abstrações e mais visibilidade do que o código realmente faz.

Uma parte de suas reclamações (ele é conhecido por suas reclamações contra C ++) é baseada no fato de que mais pessoas adotam C ++ e escrevem código sem realmente entender o que algumas das abstrações ocultam e fazem suposições erradas.


3
Qual é o custo da iteração sobre a std::vector<bool>alteração de cada valor? for ( std::vector<bool>::iterator it = v.begin(), end = v.end(); it != end; ++it ) { *it = !*it; }? O que é abstraído *it = !*it;?
David Rodríguez - dribeas

2
Embora possa ser injusto para pegar em abominações linguísticas específicas amplamente criticadas como erros ...
Fred Nurk

2
@ Fred Nurk: std::vector<bool>é um erro bem conhecido, mas é realmente um bom exemplo do que está sendo discutido: abstrações são boas, mas é preciso ter cuidado com o que elas ocultam. O mesmo pode e acontecerá no código do usuário. Para iniciantes, eu vi pessoas em C ++ e Java usando exceções para executar o controle de fluxo e código que se parece com uma chamada de função de aninhamento que é realmente um lançador de exceção de resgate: void endOperation();implementado como throw EndOperation;. Um bom programador evitará essas construções surpreendentes , mas o fato é que você pode encontrá-las.
David Rodríguez - dribeas

5
Um dos pontos de Torvalds é que: ele pode afastar os iniciantes apenas escolhendo C em C ++ (parece haver mais iniciantes em C ++) e o C ++, sendo mais complexo, tem uma curva de aprendizado mais íngreme e há mais chances de tropeçar em uma caixa de canto .
David Rodríguez - dribeas

2
+1, é exatamente disso que Linus está reclamando. Ele parece ser anti-C ++, mas não é bem assim. Ele é apenas um programador anti-C ++.
58711 greyfade

13

Uso excessivo de try/catchblocos.

File file("some.txt");
try
{
  /**/

  file.close();
}
catch(std::exception const& e)
{
  file.close();
}

Isso geralmente decorre de linguagens como Java e as pessoas argumentam que o C ++ não possui uma finalizecláusula.

Mas esse código exibe dois problemas:

  • É necessário criar fileantes do arquivo try/catch, porque você não pode realmente closeum arquivo que não existe catch. Isso leva a um "vazamento de escopo" filevisível após o fechamento. Você pode adicionar um bloco, mas ...: /
  • Se alguém aparecer e adicionar um returnno meio do tryescopo, o arquivo não será fechado (é por isso que as pessoas reclamam da falta de finalizecláusula)

No entanto, em C ++, temos maneiras muito mais eficientes de lidar com esse problema que:

  • Java's finalize
  • C # using
  • Go's defer

Temos o RAII, cuja propriedade realmente interessante é melhor resumida como SBRM(Gerenciamento de recursos limitados no escopo).

Ao criar a classe para que seu destruidor limpe os recursos que possui, não colocamos o ônus de gerenciar o recurso em todos e cada usuário!

Esse é o recurso que sinto falta em qualquer outro idioma, e provavelmente o mais esquecido.

A verdade é que raramente é necessário escrever um try/catchbloco em C ++, além do nível superior, para evitar o término sem o log.


11
Eu não acho que é a influência de Java, tanto quanto do C. (Você poderia substituir diretamente fopene fcloseaqui.) RAII é a maneira "correta" de fazer as coisas aqui, mas é inconveniente para as pessoas que querem usar bibliotecas C do C ++ .
11126 dan04

Para esse tipo de resposta, fornecer um exemplo da solução correta seria apropriado.
Claus Jørgensen

@ ClausJørgensen: Bem, a solução, infelizmente, não é realmente "vistoso", uma vez que envolve apenas File file("some.txt");e é isso (não open, não close, não try...)
Matthieu M.

D também tem RAII
Demi

@ Demetri: Eu não estou muito familiarizado com D, você poderia explicar como a RAII interage com a Garbage Collection? Eu sei que no Python você pode escrever um método "deinit", no entanto, a documentação avisa que, em caso de ciclo de referências, alguns objetos não verão o método deinit chamado.
Matthieu M. 26/03

9

Um erro comum que se encaixa nos seus critérios é não entender como os construtores de cópias funcionam ao lidar com a memória alocada em sua classe. Eu perdi a conta da quantidade de tempo que gastei consertando falhas ou vazamentos de memória porque um 'noob' colocou seus objetos em um mapa ou vetor e não escreveu construtores e destruidores de cópia adequadamente.

Infelizmente, o C ++ está cheio de truques 'ocultos' como esse. Mas reclamar é como reclamar que você foi à França e não conseguiu entender o que as pessoas estavam dizendo. Se você for para lá, aprenda o idioma.


11
Acho que o problema com o C ++ é que é muito fácil dar um tiro no próprio pé. Claro, existem bons programadores de C ++ por aí, muitos softwares bons escritos em C ++. Mas é muito difícil se tornar um bom desenvolvedor de C ++. A série 'Efficient C ++' de Scott Meyers mostra quantas sutilezas a linguagem possui.
Marco Mustapic

Concordo. Parte do problema, porém, é que muitos (a maioria) dos programadores de C ++ acham que sabem o que estão fazendo quando claramente não sabem. Você quis dizer "C ++ eficaz"?
Henry

Pelo menos isso está melhorando com as novas regras bastante restritivas sobre a geração implícita de operações de copiar / mover no C ++ 0x. Em muitos dos casos de violação da regra de três, a geração implícita de operações de cópia será descontinuada e deverá gerar um aviso.
sellibitze

6

O C ++ permite uma grande variedade de recursos e estilos de programação, mas isso não significa que essas são realmente boas maneiras de o C ++ ser usado. E, de fato, é incrivelmente fácil usar o C ++ incorretamente.

Ele precisa ser aprendido e entendido adequadamente , apenas o aprendizado (ou o uso como se fosse usar outra linguagem) levará a códigos ineficientes e propensos a erros.


4

Bem ... Para começar, você pode ler o C ++ FAQ Lite

Então, várias pessoas criaram carreiras escrevendo livros sobre os meandros do C ++:

Herb Sutter e Scott Meyers, a saber.

Quanto ao discurso retórico de Torvalds, falta substância ... vamos às pessoas, sério: nenhuma outra língua lá fora teve tanta tinta derramada ao lidar com as nuances da língua. Seus livros em Python, Ruby e Java se concentram em aplicativos de escrita ... seus livros em C ++ se concentram em recursos / dicas / armadilhas de linguagem boba.


11
Hmm ... javapuzzlers.com , jimbrooks.org/web/python/#Pitfalls . Eu diria que Accelerated C ++ (para um exemplo) se concentra muito mais sobre como escrever código que estes fazem ...
Jerry Coffin

11
Você mencionou alguns exemplos de recursos que apontam casos extremos nos respectivos idiomas; coisas que parecem estranhas e você não sabe ao certo como elas funcionariam (embora as coisas da lista python estejam próximas) ... O C ++ tem uma indústria inteira apontando coisas que parecem perfeitamente válidas e que se comportam de maneiras que você não espera.
red-dirt

3

A modelagem muito pesada pode não resultar em erros no início. Com o passar do tempo, porém, as pessoas precisarão modificar esse código e terão dificuldade em entender um modelo enorme. É aí que os bugs entram - o mal-entendido causa comentários "Compila e executa", que geralmente levam a um código quase-mas-não-muito-correto.

Geralmente, se me vejo criando um modelo genérico profundo de três níveis, paro e penso em como ele poderia ser reduzido a um. Geralmente, o problema é resolvido extraindo funções ou classes.


8
Manter códigos complicados diante das mudanças nos requisitos sempre causa bugs sem muito esforço, nada de especial nos modelos.
Fred Nurk

2

Aviso: isso não é tanto uma resposta quanto uma crítica da conversa à qual o "usuário desconhecido" vinculou em sua resposta.

Seu primeiro ponto principal é o (supostamente) "padrão sempre em mudança". Na realidade, os exemplos que ele fornece relacionam-se a alterações no C ++ antes de haver um padrão. Desde 1998 (quando o primeiro padrão C ++ foi finalizado), as alterações na linguagem foram mínimas - na verdade, muitos argumentariam que o problema real é que mais alterações deveriam ser feitas. Estou razoavelmente certo de que todo o código que está em conformidade com o padrão C ++ original ainda está em conformidade com o padrão atual. Embora seja um pouco menos certo, a menos que algo mude rapidamente (e inesperadamente), o mesmo também será verdadeiro com o próximo padrão C ++ (teoricamente, todo o código usadoexportvai quebrar, mas praticamente não existe; do ponto de vista prático, não é um problema). Posso pensar em algumas outras linguagens, sistemas operacionais (ou muitas outras coisas relacionadas ao computador) que podem fazer tal afirmação.

Ele então entra em "estilos sempre em mudança". Mais uma vez, a maioria de seus argumentos é quase absurda. Ele tenta caracterizar for (int i=0; i<n;i++)como "velho e preso" e for (int i(0); i!=n;++i)"nova gostosura". A realidade é que, embora existam tipos para os quais essas mudanças possam fazer sentido, intisso não faz diferença - e mesmo quando você pode obter algo, raramente é necessário escrever código bom ou correto. Mesmo na melhor das hipóteses, ele está fazendo uma montanha fora de uma montanha.

Sua próxima alegação é que o C ++ está "otimizando na direção errada" - especificamente, embora ele admita que o uso de boas bibliotecas seja fácil, ele afirma que o C ++ "torna quase impossível a escrita de boas bibliotecas". Aqui, acredito, é um dos seus erros mais fundamentais. Na realidade, escrever boas bibliotecas para quase qualquer idioma é extremamente difícil. No mínimo, escrever uma boa biblioteca requer a compreensão de algum domínio com problemas tão bem que seu código funciona para uma infinidade de aplicativos possíveis (ou relacionados a) nesse domínio. A maior parte do que o C ++ realmente faz é "elevar a fasquia" - depois de ver o quão melhor uma biblioteca pode ser, as pessoas raramente estão dispostas a voltar a escrever o tipo de coisa que teriam de outra forma.realmente bons codificadores escrevem algumas bibliotecas, que podem ser usadas (facilmente, como ele admite) pelo "resto de nós". Este é realmente um caso em que "isso não é um bug, é um recurso".

Não tentarei acertar todos os pontos na ordem (isso levaria páginas), mas pular diretamente para o ponto de fechamento. Ele cita Bjarne dizendo: "a otimização completa do programa pode ser usada para eliminar tabelas de funções virtuais não utilizadas e dados RTTI. Essa análise é particularmente adequada para programas relativamente pequenos que não usam vínculo dinâmico".

Ele critica isso fazendo uma afirmação sem suporte de que "Este é um problema realmente difícil", chegando até a compará-lo ao problema de parada. Na realidade, não é nada disso - de fato, o vinculador incluído no Zortech C ++ (praticamente o primeiro compilador C ++ para MS-DOS, nos anos 80) fez isso. É verdade que é difícil ter certeza de que toda parte de dados possivelmente estranhos foi eliminada, mas ainda é inteiramente razoável fazer um trabalho bastante justo.

Independentemente disso, porém, o ponto muito mais importante é que isso é totalmente irrelevante para a maioria dos programadores em qualquer caso. Como todos nós que desmontamos um pouco de código sabem, a menos que você escreva a linguagem assembly sem nenhuma biblioteca, seus executáveis ​​quase certamente contêm uma quantidade razoável de "coisas" (código e dados, em casos típicos) que você provavelmente nem sabe, para não mencionar que realmente está usando. Para a maioria das pessoas, na maioria das vezes, isso simplesmente não importa - a menos que você esteja desenvolvendo para os menores sistemas embarcados, esse consumo extra de armazenamento é simplesmente irrelevante.

No final, é verdade que esse discurso retórico tem um pouco mais de substância do que a idiotice de Linus - mas isso está dando a ela exatamente o maldito elogio que merece.


1

Como programador em C que teve que codificar em C ++ devido a circunstâncias inevitáveis, aqui está minha experiência. Há muito poucas coisas que uso em C ++ e, principalmente, em C. A principal razão é porque eu não entendo C ++ tão bem. Eu não tinha / não tinha um mentor para me mostrar os meandros do C ++ e como escrever um bom código nele. E sem a orientação de um código C ++ muito bom, é extremamente difícil escrever um código bom em C ++. IMHO, essa é a maior desvantagem do C ++, porque é difícil encontrar bons codificadores de C ++ dispostos a segurar iniciantes.

Alguns dos hits de desempenho que eu vi geralmente são devidos à alocação de memória mágica do STL (sim, você pode alterar o alocador, mas quem faz isso quando ele inicia o C ++?). Você costuma ouvir argumentos de especialistas em C ++ de que vetores e matrizes oferecem desempenho semelhante, porque os vetores usam matrizes internamente e a abstração é super eficiente. Eu descobri que isso é verdade na prática para acessar vetores e modificar valores existentes. Mas não é verdade para adicionar uma nova entrada, construção e destruição de vetores. O gprof mostrou que cumulativamente 25% do tempo para um aplicativo era gasto em construtores de vetores, destruidores, memmove (para realocação de vetores inteiros para adicionar novo elemento) e outros operadores de vetores sobrecarregados (como ++).

Na mesma aplicação, o vetor de somethingSmall foi usado para representar um somethingBig. Não havia necessidade de acesso aleatório de algo pequeno em algo grande. Ainda um vetor foi usado em vez de uma lista. A razão pela qual o vetor foi usado? Como o codificador original estava familiarizado com a matriz como sintaxe de vetores e não muito familiarizado com os iteradores necessários para as listas (sim, ele é do fundo C). Continua a provar que é necessária muita orientação de especialistas para acertar o C ++. O C oferece tão poucas construções básicas com absolutamente nenhuma abstração, que você pode acertar muito mais facilmente do que o C ++.



0

STL e boost são portáteis, no nível do código-fonte. Eu acho que Linus está falando é que o C ++ não possui uma ABI (interface binária de aplicativo). Portanto, você precisa compilar todas as bibliotecas vinculadas, com a mesma versão do compilador e com as mesmas opções, ou então limitar-se à C ABI nos limites da dll. Também acho que isso é possível .. mas, a menos que você esteja criando bibliotecas de terceiros, poderá controlar o ambiente de construção. Acho que me restringir ao C ABI não vale a pena. A conveniência de poder transmitir seqüências de caracteres, vetores e ponteiros inteligentes de uma dll para outra vale a pena ter que reconstruir todas as bibliotecas ao atualizar os compiladores ou alterar as opções do compilador. As regras de ouro que sigo são:

- Herdar para reutilizar a interface, não a implementação

-Preferir agregação sobre herança

-Preferir, sempre que possível, funções livres para métodos membros

Sempre use o idioma RAII para tornar seu código altamente seguro. Evite tentar pegar.

-Use ponteiros inteligentes, evite ponteiros nus (sem dono)

-Preferir a semântica do valor para referenciar a semântica

-Não reinvente a roda, use stl e aumente

-Use o idioma Pimpl para ocultar privado e / ou fornecer um firewall de compilador


-6

Não colocando uma final ;no final de uma declaração clase, pelo menos em algumas versões do VC.


4
Talvez este seja um erro muito comum para iniciantes (como quase tudo para alguém que ainda está aprendendo a sintaxe básica), mas há muitos que se autodenominariam competentes e ainda acharão esse erro digno de nota?
Fred Nurk

11
Escreveu apenas porque o compilador deu a você um erro que não tinha nada a ver com a falta de ponto e vírgula.
9137 Marco Mustapic

2
Sim, exatamente o mesmo erro é o que você obtém de um compilador C.
Mircea Chirea
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.