É uma má prática usar um compilador C ++ apenas para sobrecarga de função?


60

Então, eu estou trabalhando em um design de software usando C para um determinado processador. O kit de ferramentas inclui a capacidade de compilar C e C ++. Para o que estou fazendo, não há alocação dinâmica de memória disponível neste ambiente e, em geral, o programa é bastante simples. Sem mencionar que o dispositivo quase não possui energia ou recursos do processador. Não há realmente nenhuma necessidade forte de usar C ++.

Dito isto, há alguns lugares em que sobrecarrego as funções (um recurso do C ++). Preciso enviar alguns tipos diferentes de dados e não sinto vontade de usar a printfformatação de estilo com algum tipo de %sargumento (ou o que seja). Eu já vi algumas pessoas que não tiveram acesso a um compilador C ++ fazendo printfisso, mas no meu caso, o suporte a C ++ está disponível.

Agora eu tenho certeza que posso ter a pergunta de por que preciso sobrecarregar uma função para começar. Então, vou tentar responder isso agora. Preciso transmitir diferentes tipos de dados por uma porta serial, para que haja algumas sobrecargas que transmitam os seguintes tipos de dados:

unsigned char*
const char*
unsigned char
const char

Eu preferiria não ter um método que lida com todas essas coisas. Quando eu chamo a função, eu só quero que ela transmita a porta serial, não tenho muitos recursos, então não quero fazer quase nada além da minha transmissão.

Outra pessoa viu meu programa e me perguntou: "por que você está usando arquivos CPP?" Então, essa é a minha única razão. Isso é uma prática ruim?

Atualizar

Gostaria de abordar algumas perguntas:

Uma resposta objetiva ao seu dilema dependerá de:

  1. Se o tamanho do executável aumenta significativamente se você usar C ++.

No momento, o tamanho do executável consome 4,0% da memória do programa (de 5248 bytes) e 8,3% da memória de dados (de 342 bytes). Ou seja, compilando para C ++ ... Eu não sei como seria para C porque eu não estava usando o compilador C. Eu sei que este programa não crescerá mais, então, por quão limitados os recursos, eu diria que estou bem lá ...

  1. Se existe algum impacto negativo perceptível no desempenho se você usar C ++.

Bem, se houver, não notei nada ... mas, novamente, pode ser por isso que estou fazendo essa pergunta, pois não entendo completamente.

  1. Se o código pode ser reutilizado em uma plataforma diferente, onde apenas um compilador C está disponível.

Eu sei que a resposta para isso é definitivamente não . Na verdade, estamos pensando em mudar para um processador diferente, mas apenas processadores mais poderosos baseados em ARM (todos os quais eu sei de fato possuem cadeias de ferramentas de compilador C ++).


59
Eu sou conhecido por usar C ++ para um projeto usando apenas recursos C apenas para que eu possa ter //comentários. Se funcionar, por que não?
Jules

76
A prática recomendada seria restringir-se a C quando você usar bem os recursos que ele não fornece.
Jerry Coffin

35
Quando você diz "use um compilador C ++", você quer dizer "use C ++". Apenas diga. Você não pode compilar C com um compilador C ++, mas pode alternar de C para C ++ facilmente, que é o que você realmente faria.
user253751

4
"Para o que estou fazendo, não há alocação dinâmica de memória no processador e o programa é bastante simples. Sem mencionar que o dispositivo quase não possui poder ou recursos do processador. Não há realmente uma forte necessidade de usar C ++." Espero que a primeira dessas duas frases deva ser razões para não usar C ++, porque são muito ruins se forem. C ++ é perfeitamente adequado para uso com sistemas embarcados.
Pharap

21
@ Jules Tenho certeza que você sabe disso e estava pensando um pouco, mas no caso de alguém ler isso não: os //comentários estão no padrão C desde C99.
Davislor

Respostas:


77

Eu não chegaria a chamá-lo de "má prática" por si só , mas também não estou convencido de que seja realmente a solução certa para o seu problema. Se tudo o que você deseja são quatro funções separadas para executar seus quatro tipos de dados, por que não fazer o que os programadores C fizeram desde tempos imemoriais:

void transmit_uchar_buffer(unsigned char *buffer);
void transmit_char_buffer(char *buffer);
void transmit_uchar(unsigned char c);
void transmit_char(char c);

Isso é efetivamente o que o compilador C ++ está fazendo nos bastidores de qualquer maneira e não é uma sobrecarga para o programador. Evita todos os problemas de "por que você está escrevendo um C-não-muito-C com um compilador C ++" e significa que ninguém mais no seu projeto ficará confuso com quais bits de C ++ são "permitidos" e quais não são.


8
Eu diria por que não, porque o tipo que está sendo transmitido é (provavelmente) um detalhe da implementação, portanto, escondê-lo e permitir que o compilador lide com a seleção da implementação pode resultar em um código mais legível. E se o uso de um recurso C ++ melhora a legibilidade, por que não fazer isso?
Jules

29
Pode-se até #definetransmitir () usando C11_Generic
Deduplicator

16
@Jules Porque é muito confuso quanto aos recursos do C ++ que podem ser usados ​​no projeto. Uma mudança em potencial contendo objetos seria rejeitada? E os modelos? Comentários no estilo C ++? Claro, você pode contornar isso com um documento de estilo de codificação, mas se tudo o que você está fazendo é um simples caso de sobrecarga de função, basta escrever C.
Philip Kendall

25
@Phillip "Comentários no estilo C ++" são válidos em C há mais de uma década.
21817 David Conrad

12
@Jules: enquanto o tipo que está sendo transmitido é provavelmente um detalhe de implementação do software que faz cotações de seguro, o aplicativo dos OPs parece ser um sistema incorporado que faz comunicação serial, onde o tipo e o tamanho dos dados são de importância significativa.
Whatsisname

55

Usar apenas alguns recursos do C ++ enquanto o trata como C não é exatamente comum, mas também não é exatamente inédito. Na verdade, algumas pessoas ainda utilizam características em todos C ++, exceto a mais rigorosa e mais poderoso tipo de verificação. Eles simplesmente escrevem C (tendo o cuidado de escrever apenas na interseção comum de C ++ e C), depois compilam com um compilador C ++ para verificação de tipo e um compilador C para geração de código (ou simplesmente fica com um compilador C ++ todo o caminho).

O Linux é um exemplo de uma base de código em que as pessoas solicitam regularmente que identificadores como classsejam renomeados para klassou kclass, para que possam compilar o Linux com um compilador C ++. Obviamente, dada a opinião de Linus sobre C ++ , eles sempre são abatidos :-D GCC é um exemplo de uma base de código que foi primeiro transformada em "C ++ - clean C" e depois gradualmente refatorada para usar mais recursos de C ++.

Não há nada errado com o que você está fazendo. Se você é realmente paranóico com a qualidade de geração de código do seu compilador C ++, pode usar um compilador como o Comeau C ++, que é compilado em C como idioma de destino e, em seguida, use o compilador C. Dessa forma, você também pode fazer inspeções pontuais do código para verificar se o uso do C ++ injeta algum código sensível ao desempenho imprevisto. Esse não deve ser o caso de sobrecarregar, porém, que literalmente gera automaticamente funções com nomes diferentes - IOW, exatamente o que você faria em C de qualquer maneira.


15

Uma resposta objetiva ao seu dilema dependerá de:

  1. Se o tamanho do executável aumenta significativamente se você usar C ++.
  2. Se existe algum impacto negativo perceptível no desempenho se você usar C ++.
  3. Se o código pode ser reutilizado em uma plataforma diferente, onde apenas um compilador C está disponível.

Se a resposta para qualquer uma das perguntas for "sim", é melhor criar funções com nomes diferentes para diferentes tipos de dados e seguir C.

Se as respostas para todas as perguntas forem "não", não vejo razão para você não usar C ++.


9
Devo dizer que nunca encontrei um compilador C ++ que gera código significativamente pior do que um compilador C para código escrito no subconjunto compartilhado das duas linguagens. Os compiladores C ++ obtêm uma reputação ruim tanto em tamanho quanto em desempenho, mas minha experiência é sempre o uso inadequado dos recursos do C ++ que causaram o problema ... Particularmente, se você estiver preocupado com o tamanho, não use iostreams e não use modelos, mas, caso contrário, você deve ficar bem.
Jules

@ Jules: Só pelo que vale a pena (não muito, IMO) Eu vi o que foi vendido como um compilador único para C e C ++ (Turbo C ++ 1.0, se a memória servir) produzem resultados significativamente diferentes para entradas idênticas. Pelo que entendi, no entanto, isso foi antes de eles terminarem seu próprio compilador C ++, portanto, embora parecesse um compilador do lado de fora, ele realmente tinha dois compiladores totalmente separados - um para C e outro para C ++.
Jerry Coffin

11
@JerryCoffin Se a memória serve, os produtos Turbo nunca tiveram uma grande reputação. E se fosse uma versão 1.0, você poderia ser desculpado por não ser altamente refinado. Portanto, provavelmente não é muito representativo.
Barmar

10
@ Barmar: Na verdade, eles tiveram uma reputação bastante decente por um bom tempo. Sua má reputação agora se deve principalmente à sua pura idade. Eles são competitivos com outros compiladores da mesma safra - mas ninguém posta perguntas sobre como fazer as coisas com o gcc 1.4 (ou o que seja). Mas você está certo - não é muito representativo.
Jerry Coffin

11
@ Jules Eu diria que até modelos são bons. Apesar da teoria popular, instanciar um modelo não aumenta implicitamente o tamanho do código, o tamanho do código geralmente não aumenta até que uma função de um modelo seja usada (nesse caso, o aumento do tamanho será proporcional ao tamanho da função) ou a menos que o modelo seja declarando variáveis ​​estáticas. As regras de inlining ainda se aplicam, portanto, é possível escrever modelos onde todas as funções são incorporadas pelo compilador.
precisa saber é o seguinte

13

Você coloca a questão como se a compilação com C ++ simplesmente desse acesso a mais recursos. Este não é o caso. Compilar com um compilador C ++ significa que seu código-fonte é interpretado como fonte C ++, e C ++ é uma linguagem diferente de C. Os dois têm um subconjunto comum grande o suficiente para programar de maneira útil, mas cada um possui recursos que o outro não possui, e é possível escrever código aceitável nos dois idiomas, mas interpretado de maneira diferente.

Se realmente tudo o que você deseja é sobrecarregar funções, então eu realmente não vejo o ponto de confundir o problema trazendo C ++ para ele. Em vez de funções diferentes com o mesmo nome, distinguidas suas listas de parâmetros, basta escrever funções com nomes diferentes.

Quanto aos seus critérios objetivos,

  1. Se o tamanho do executável aumenta significativamente se você usar C ++.

O executável pode ser um pouco maior quando compilado como C ++, em relação ao código C semelhante criado como tal. No mínimo, o executável do C ++ terá o benefício duvidoso da manipulação de nomes do C ++ para todos os nomes de funções, na medida em que quaisquer símbolos sejam retidos no executável. (E é de fato o que fornece suas sobrecargas em primeiro lugar.) Se a diferença é grande o suficiente para ser importante para você, é algo que você precisaria determinar por experiência.

  1. Se existe algum impacto negativo perceptível no desempenho se você usar C ++.

Duvido que você tenha notado uma diferença notável de desempenho para o código que você descreve em comparação com um hipotético análogo de C puro.

  1. Se o código pode ser reutilizado em uma plataforma diferente, onde apenas um compilador C está disponível.

Eu colocaria uma luz um pouco diferente sobre isso: se você deseja vincular o código que está criando com C ++ a outro código, esse outro código também precisará ser escrito em C ++ e criado com C ++, ou será necessário para fazer provisões especiais em seu próprio código (declarando ligação "C"), o que, além disso, você não pode fazer por suas funções sobrecarregadas. Por outro lado, se o seu código for escrito em C e compilado como C, outros poderão vinculá-lo aos módulos C e C ++. Esse tipo de problema geralmente pode ser superado ao virar a mesa, mas como você realmente não parece precisar de C ++, por que aceitar esse problema em primeiro lugar?


4
"O executável pode ser um pouco maior quando compilado como C ++ ... na medida em que quaisquer símbolos são retidos no executável." Para ser justo, porém, qualquer cadeia de ferramentas de otimização decente deve ter uma opção de vinculador para remover esses símbolos nas compilações "release", o que significa que elas apenas inchariam suas compilações de depuração. Não acho que seja uma grande perda. De fato, é mais frequentemente um benefício.
Cody Grey #

5

Antigamente, o uso de um compilador C ++ como "um C melhor" era promovido como um caso de uso. De fato, o C ++ inicial era exatamente isso. O princípio de design subjacente era que você poderia usar apenas os recursos desejados e não incorreria no custo dos recursos que não estava usando. Portanto, você poderia sobrecarregar as funções (declarando a intenção por meio da overloadpalavra - chave!) E o restante do seu projeto não apenas compilaria bem, como também geraria código não pior do que o compilador C produziria.

Desde então, os idiomas divergiram um pouco.

Cada malloccódigo C será um erro de incompatibilidade de tipo - não é um problema no seu caso, sem memória dinâmica! Da mesma forma, todos os seus voidponteiros em C o enganarão, pois você precisará adicionar moldes explícitos. Mas ... por que você está fazendo dessa maneira ? Você será levado ao caminho do uso de recursos C ++ cada vez mais.

Portanto, pode ser possível com algum trabalho extra. Mas servirá como porta de entrada para a adoção de C ++ em maior escala. Em alguns anos, as pessoas reclamarão do seu código legado que parece ter sido escrito em 1989, à medida que substituem suas mallocchamadas new, eliminam blocos de código de corpos de loop para chamar um algoritmo e repreendem o polimorfismo falso inseguro que foram triviais se o compilador tivesse permissão para fazê-lo.

Por outro lado, você sabe que tudo seria o mesmo se você o tivesse escrito em C, então é errado escrever em C em vez de C ++, dada a sua existência? Se a resposta for "não", o uso de recursos escolhidos a dedo no C ++ também não pode estar errado .


2

Muitas linguagens de programação têm uma ou mais culturas que se desenvolvem à sua volta e têm idéias particulares sobre o que uma linguagem deveria "ser". Embora deva ser possível, prático e útil ter uma linguagem de baixo nível adequada para programação de sistemas que amplie um dialeto de C adequado para esse fim com alguns recursos do C ++ que também seriam adequados, as culturas que cercam os dois idiomas não ' favorece particularmente essa fusão.

Eu li sobre um compilador C incorporado que incorporou alguns recursos do C ++, incluindo a capacidade de ter

foo.someFunction(a,b,c);

interpretado como, essencialmente

typeOfFoo_someFunction(foo, a, b, c);

bem como a capacidade de sobrecarregar funções estáticas (os problemas de confusão de nomes surgem apenas quando exportadosfunções estão sobrecarregadas). Não há razão para que os compiladores C não possam suportar essa funcionalidade sem impor requisitos adicionais no ambiente de link e tempo de execução, mas a rejeição reflexiva de muitos compiladores C de quase tudo, desde C ++, a fim de evitar encargos ambientais, faz com que eles rejeitar até recursos que não imporiam esse custo. Enquanto isso, a cultura do C ++ tem pouco interesse em qualquer ambiente que não possa suportar todos os recursos dessa linguagem. A menos que ou até que a cultura de C seja alterada para aceitar esses recursos ou que a cultura de C ++ seja alterada para incentivar implementações de subconjuntos leves, o código "híbrido" pode sofrer muitas das limitações de ambos os idiomas, embora seja limitado em sua capacidade de colher os benefícios de operar em um superconjunto combinado.

Se uma plataforma suportar C e C ++, o código extra da biblioteca necessário para suportar C ++ provavelmente tornará o executável um pouco maior, embora o efeito não seja particularmente grande. A execução de "recursos C" no C ++ provavelmente não será afetada. Um problema maior pode ser como os otimizadores de C e C ++ lidam com vários casos de canto. O comportamento dos tipos de dados em um C é definido principalmente pelo conteúdo dos bits armazenados nele, e o C ++ possui uma categoria reconhecida de estruturas (PODS - Plain Old Data Structures) cuja semântica também é definida principalmente pelos bits armazenados. Os padrões C e C ++, no entanto, às vezes permitem comportamentos contrários aos implícitos nos bits armazenados, e as exceções ao comportamento dos "bits armazenados" diferem entre os dois idiomas.


11
Opinião interessante, mas não aborda a questão do OP.
R: Sahu

@RSahu: O código que se encaixa na "cultura" em torno de um idioma pode ser melhor suportado e mais facilmente adaptável a uma variedade de implementações do que o código que não é. As culturas de C e C ++ são avessas ao tipo de uso sugerido pelo OP, acrescentarei alguns pontos mais específicos em relação às perguntas específicas.
Supercat

11
Observe que há um grupo incorporado / financeiro / de jogos no comitê padrão do C ++ que visa solucionar exatamente o tipo de "pouco interesse" que você afirma ter sido descartado.
Yakk

@Yakk: Confesso que não tenho acompanhado o mundo C ++ terrivelmente de perto, já que meus interesses estão principalmente em C; Eu sei que houve esforços em direção a mais dialetos incorporados, mas eu não pensei que eles realmente tivessem chegado a lugar algum.
Supercat

2

Outro fator importante a considerar: quem herdará seu código.

Essa pessoa sempre será um programador C com um compilador C? Eu suponho que sim.

Essa pessoa também será um programador de C ++ com um compilador de C ++? Eu gostaria de ter uma certeza razoável sobre isso antes de fazer meu código depender de coisas específicas do C ++.


2

O polimorfismo é um recurso muito bom que o C ++ fornece gratuitamente. No entanto, existem outros aspectos que você pode precisar considerar ao escolher um compilador. Existe uma alternativa para o polimorfismo em C, mas seu uso pode causar sobrancelhas levantadas. É a função variável, consulte o tutorial da função variável .

No seu caso, seria algo como

enum serialDataTypes
{
 INT =0,
 INT_P =1,
 ....
 }Arg_type_t;
....
....
void transmit(Arg_type_t serial_data_type, ...)
{
  va_list args;
  va_start(args, serial_data_type);

  switch(serial_data_type)
  {
    case INT: 
    //Send integer
    break;

    case INT_P:
    //Send data at integer pointer
    break;
    ...
   }
 va_end(args);
}

Eu gosto da abordagem Phillips, mas ela enche sua biblioteca de muitas chamadas. Com o exposto acima, a interface está limpa. Ele tem suas desvantagens e, finalmente, é uma questão de escolha.


As funções variadicas atendem principalmente ao caso de uso em que o número de argumentos e seus tipos são variáveis. Caso contrário, você não precisa e, em particular, é um exagero para o seu exemplo em particular. Seria mais simples usar uma função comum que aceite um Arg_type_te um void *apontador para os dados. Com isso dito, sim, atribuir à função (única) um argumento que indique o tipo de dados é realmente uma alternativa viável.
John Bollinger

1

Para o seu caso particular de sobrecarregar estaticamente uma "função" para alguns tipos diferentes, você pode considerar usar o C11 com seu mecanismo de _Genericmacro . Eu sinto que pode ser suficiente para suas necessidades limitadas.

Usando a resposta de Philip Kendall, você pode definir:

#define transmit(X) _Generic((X),      \
   unsigned char*: transmit_uchar_buffer, \
   char*: transmit_char_buffer,           \
   unsigned char: transmit_uchar,         \
   char: transmit_char) ((X))

e codifique transmit(foo) qualquer que seja o tipo de foo(entre os quatro tipos listados acima).

Se você se importa apenas com os compiladores GCC (e compatíveis, por exemplo, Clang ), considere __builtin_types_compatible_psua typeofextensão.


1

É uma má prática usar um compilador C ++ apenas para sobrecarga de função?

Ponto de vista do IMHO, sim, e precisarei me tornar esquizofrênico para responder a este, já que amo os dois idiomas, mas não tem nada a ver com eficiência, mas mais como segurança e uso idiomático de idiomas.

Lado C

Do ponto de vista de C, acho tão inútil fazer com que seu código exija C ++ apenas para usar a sobrecarga de funções. A menos que você o esteja utilizando para polimorfismo estático com modelos C ++, é um açúcar sintático tão trivial obtido em troca da mudança para uma linguagem totalmente diferente. Além disso, se você quiser exportar suas funções para um dylib (pode ou não ser uma preocupação prática), não poderá mais fazê-lo na prática para um consumo generalizado com todos os símbolos com nomes diferentes.

Lado C ++

Do ponto de vista de C ++, você não deve usar C ++ como C com sobrecarga de função. Este não é um dogmatismo estilístico, mas um relacionado ao uso prático do C ++ cotidiano.

Seu tipo normal de código C é razoavelmente sensato e "seguro" para escrever se você estiver trabalhando com o sistema de tipo C que proíbe coisas como copiadores de conteúdo structs. Quando você trabalha no sistema de tipos muito mais rico em C ++, as funções diárias que são de enorme valor memsete memcpynão se tornam funções nas quais você deve se apoiar o tempo todo. Em vez disso, são funções que você geralmente deseja evitar como uma praga, já que com os tipos C ++, você não deve tratá-los como bits e bytes brutos para serem copiados, embaralhados e liberados. Mesmo que seu código use apenas coisas como memsetprimitivas e UDTs de POD no momento, no momento em que alguém adicionar um ctor a qualquer UDT que você usar (incluindo apenas a adição de um membro que exija um, comostd::unique_ptrmembro) contra essas funções ou uma função virtual ou qualquer coisa desse tipo, torna toda a sua codificação normal no estilo C suscetível a comportamento indefinido. Tomemos do próprio Herb Sutter:

memcpye memcmpviolar o sistema de tipos. Usar memcpypara copiar objetos é como ganhar dinheiro usando uma fotocopiadora. Usar memcmppara comparar objetos é como comparar leopardos contando seus pontos. As ferramentas e métodos podem parecer fazer o trabalho, mas são muito grosseiros para fazê-lo de maneira aceitável. Objetos C ++ têm tudo a ver com ocultação de informações (sem dúvida o princípio mais lucrativo em engenharia de software; consulte o Item 11): os objetos ocultam dados (consulte o Item 41) e criam abstrações precisas para copiar esses dados por meio de construtores e operadores de atribuição (consulte os itens 52 a 55) . Fazer um bulldozing sobre tudo isso com memcpyuma violação grave da ocultação de informações e geralmente leva a vazamentos de memória e recursos (na melhor das hipóteses), falhas (pior) ou comportamento indefinido (pior) - Padrões de Codificação C ++.

Muitos desenvolvedores de C discordariam disso e com razão, pois a filosofia se aplica se você estiver escrevendo código em C ++. Você provavelmente está escrevendo código muito problemático se você usar funções como memcpytodos os tempos no código que constrói como C ++ , mas é perfeitamente bem se você fizer isso em C . Os dois idiomas são muito diferentes nesse aspecto, devido às diferenças no sistema de tipos. É muito tentador olhar para o subconjunto de recursos que esses dois têm em comum e acredita que um pode ser usado como o outro, especialmente no lado C ++, mas o código C + (ou código C--) geralmente é muito mais problemático do que C e Código C ++.

Da mesma forma, você não deve estar usando, digamos, mallocem um contexto de estilo C (que não implica EH) se ele puder chamar diretamente qualquer função C ++ que possa ser lançada, desde então, você tem um ponto de saída implícito em sua função como resultado do exceção que você não pode pegar efetivamente escrevendo código em estilo C, antes de poder freeacessar essa memória. Assim, sempre que você tem um arquivo que constrói como C ++ com uma .cppextensão ou qualquer outra coisa e ele faz todos esses tipos de coisas como malloc, memcpy, memset,qsort, etc, então ele está solicitando problemas mais adiante, se não já, a menos que sejam os detalhes de implementação de uma classe que funcione apenas com tipos primitivos; nesse momento, ainda é necessário fazer o tratamento de exceções para garantir sua segurança. Se você estiver escrevendo código C ++ você em vez quer confiar geralmente em RAII e usar coisas como vector, unique_ptr, shared_ptr, etc, e evitar qualquer codificação normais de estilo C, quando possível.

A razão pela qual você pode brincar com lâminas de barbear nos tipos de dados C e raios-X e brincar com seus bits e bytes sem propensão a causar danos colaterais em uma equipe (embora você ainda possa se machucar de qualquer maneira) não é por causa do que C tipos podem fazer, mas por causa do que eles nunca serão capazes de fazer. No momento em que você estende o sistema de tipos do C para incluir recursos do C ++, como ctors, dtors e vtables, junto com o tratamento de exceções, todo o código C idiomático seria renderizado muito, muito mais perigoso do que é atualmente, e você verá um novo tipo de evolução da filosofia e da mentalidade que encorajará um estilo de codificação completamente diferente, como você vê em C ++, que agora considera o uso de uma má prática bruta de ponteiro para uma classe que gerencia a memória em vez de, por exemplo, um recurso compatível com RAII unique_ptr. Essa mentalidade não evoluiu de uma sensação absoluta de segurança. Ele evoluiu a partir do que o C ++ especificamente precisa ser seguro contra recursos como o tratamento de exceções, considerando o que apenas permite através de seu sistema de tipos.

Exceção-Segurança

Novamente, no momento em que você estiver no país C ++, as pessoas esperam que seu código seja seguro contra exceções. As pessoas podem manter seu código no futuro, já que ele já está escrito e compilado em C ++ e simplesmente usa std::vector, dynamic_cast, unique_ptr, shared_ptretc. no código chamado direta ou indiretamente pelo seu código, acreditando ser inócuo, pois seu código já é "supostamente" C ++ código. Nesse ponto, temos que enfrentar a chance de as coisas acontecerem e, então, quando você usar um código C perfeitamente bom e adorável, como este:

int some_func(int n, ...)
{
    int* x = calloc(n, sizeof(int));
    if (x)
    {
        f(n, x); // some function which, now being a C++ function, may 
                 // throw today or in the future.
        ...
        free(x);
        return success;
    }
    return fail;
}

... agora está quebrado. Ele precisa ser reescrito para ter uma exceção segura:

int some_func(int n, ...)
{
    int* x = calloc(n, sizeof(int));
    if (x)
    {
        try
        {
            f(n, x); // some function which, now being a C++ function, may 
                     // throw today or in the future (maybe someone used
                     // std::vector inside of it).
        }
        catch (...)
        {
            free(x);
            throw;
        }
        ...
        free(x);
        return success;
    }
    return fail;
}

Bruto! É por isso que a maioria dos desenvolvedores de C ++ exigiria isso:

void some_func(int n, ...)
{
    vector<int> x(n);
    f(x); // some function which, now being a C++ function, may throw today
          // or in the future.
}

O código acima é um código de exceção segura compatível com RAII, do tipo que os desenvolvedores de C ++ geralmente aprovariam, pois a função não vazará, nenhuma linha de código que desencadeia uma saída implícita como resultado de a throw.

Escolha um idioma

Você deve adotar o sistema de tipos e a filosofia do C ++ com RAII, segurança de exceção, modelos, OOP etc. ou adotar o C, que gira amplamente em torno de bits e bytes brutos. Você não deve formar um casamento profano entre esses dois idiomas e, em vez disso, separá-los em idiomas distintos para serem tratados de maneira muito diferente em vez de confundi-los.

Esses idiomas querem se casar com você. Você geralmente tem que escolher um em vez de namorar e brincar com os dois. Ou você pode ser um polígamo como eu e se casar com os dois, mas precisa mudar completamente seu pensamento ao passar um tempo um com o outro e mantê-los bem separados um do outro para que não briguem.

Tamanho binário

Por curiosidade, tentei pegar minha implementação de lista grátis e referência agora e portá-la em C ++, pois fiquei realmente curiosa sobre isso:

[...] não sei como seria o C porque não uso o compilador C.

... e queria saber se o tamanho binário seria inflado apenas criando como C ++. Isso exigiu que eu espalhasse elencos explícitos em todo o lugar, que era fugaz (uma razão pela qual eu gosto de escrever coisas de baixo nível, como alocadores e estruturas de dados em C, melhor), mas levou apenas um minuto.

Isso estava apenas comparando uma compilação de versão de MSVC de 64 bits para um aplicativo simples de console e com código que não usava nenhum recurso de C ++, nem mesmo sobrecarga de operador - apenas a diferença entre compilar com C e usar, digamos, em <cstdlib>vez de <stdlib.h>e coisas assim, mas fiquei surpreso ao descobrir que não fazia diferença nenhuma no tamanho binário!

O binário era 9,728bytes quando foi criado em C e da mesma forma 9,278bytes quando compilado como código C ++. Na verdade, eu não esperava isso. Eu pensei que coisas como EH ao menos adicionariam um pouco lá (pensei que seria pelo menos cem bytes diferentes), embora provavelmente ele fosse capaz de descobrir que não havia necessidade de adicionar instruções relacionadas ao EH, pois eu sou apenas usando a biblioteca padrão C e nada lança. Eu pensei em algoadicionaria um pouco ao tamanho binário de qualquer maneira, como RTTI. Enfim, foi legal ver isso. É claro que não acho que você deva generalizar a partir desse resultado, mas pelo menos isso me impressionou um pouco. Também não causou impacto nos benchmarks, e naturalmente, pois eu imagino que o tamanho binário resultante idêntico também significou instruções de máquina resultantes idênticas.

Dito isto, quem se importa com o tamanho binário dos problemas de segurança e engenharia mencionados acima? Então, novamente, escolha uma linguagem e adote sua filosofia em vez de tentar bastardizá-la; é isso que eu recomendo.

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.