· D vs C/C++/C#/Java · Rationale for Builtins · Converting C to D · Converting C++ to D · The C Preprocessor vs D · D strings vs C++ std::string · D complex vs C++ std::complex · D Contract Programming vs C++ |
Strings em D vs Strings em C++Por que ter strings na linguagem núcleo de D ao invés de inteiramente em uma biblioceta como strings em C++? Por que esse ponto? Onde está a melhoria?Operador de ConcatenaçãoStrings em C++ são cravadas com a sobrecarga de operadores existentes A escolha óbvia para concatenação é += e +. Mas alguns apenas olhando para o código irão ver + e pensar "adição". Eles terão que buscar os tipos (e tipos são freqüêntemente entarrados atrás de múltplos typedef's) para ver que é um tipo string, e não está somando strings mas sim concatenando-as.Adicionalmente, se alguém tem uma ordem de floats, é '+' sobrecarregado para ser o mesmo que adição de ordens ou concatenação de ordens? Em D, estes problemas são evitados introduzindo um novo operador binário ~ como operador de concatenação. Ele trabalha com ordens (das quais strings são um subconjunto). ~= é o operador de junção correspondente. ~ em ordens de floats seria concatená-los, + seria insinuar uma soma de vetor. Adicionar um novo operador torna possível ortogonalidade e consistência no tratamento de ordens. (Em D, strings são simples ordens de caracteres, não um tipo especial.) Interoperabilidade com a Sintaxe de String de CSobrecarga de operadores trabalha somente se um dos operandos for sobrecarregável. Então a classe string do C++ não pode controlar consistentemente expressões arbitrárias contento strings. Considere:const char abc[5] = "world";Que não trabalhará. Mas isso trabalha quando a linguagem núcleo conhece strings: const char[5] abc = "world"; Consistência com a Sintaxe de String de CHá três modos de encontrar o comprimento de uma string em C++:const char abc[] = "world"; : sizeof(abc)/sizeof(abc[0])-1Esse tipo de inconsistência torna difícil escrever gabaritos genéricos. Considere D: char[5] abc = "world"; : abc.length Checando por Strings VaziasStrings em C++ usam uma função para determinar se uma string está vazia:string str;Em D, uma string vazia tem comprimento zero: char[] str; Redimensionando Strings ExistentesC++ controla isso com a função membro resize():string str;D toma vantagem de saber que str é uma string, então redimensioná-la é apenas mudar a propriedade comprimento: char[] str; Fatiando uma StringC++ fatia uma string existente usando um construtor especial:string s1 = "hello world";D tem a sintaxe de fatia de ordem, não possível em C++: char[] s1 = "hello world";Fatiar, claro, trabalha com qualquer ordem em D, não apenas strings. Copiando uma StringC++ copia strings com a função replace:string s1 = "hello world";D usa a sintaxe de fatia como um lvalue: char[] s1 = "hello world"; Conversões para Strings CIsso é necessário para compatibilidade comAPI's C. Em C++, isso usa a função membro c_str():void foo(const char *);Em D, strings podem ser implicitamente convertidas para char*: void foo(char *);Nota: alguns irão discutir que é um engano em D tem uma conversão implicita de char[] para char*. Checagem de Limites da OrdemEm C++, checagem de limites da ordem de strings para [] não é feita. Em D, checagem de limites da ordem é ligada por padrão e pode ser desligada com um interrruptor do compilador depois de o programa ser depurado.Instruções Switch com StringsNão são possíveis em C++, nem há qualquer modo de adicioná-las adicionando mais para uma biblioteca. Em D, elas tomam a forma sintática óbvia:switch (str)onde str pode ser qualquer "string" literal, strings de ordem fixa como char[10], ou strings dinâmicas como char[]. Uma implementação de qualidade pode, é claro, explorar muitas estratégias de implementar eficientemente isso baseado em conteúdos das strings caso. Preenchendo uma StringEm C++, isso é feito com a função membro replace replace():string str = "hello";Em D, use a sintaxe de fatia de ordem de forma natural: char[] str = "hello"; Valor vs ReferênciaStrings em C++, como implementadas pela STLport, são por valor e são terminadas em 0. [A mais recente é uma implementação alternativa, mas STLport parece ser a implementação mais popular.] Isso, com a falta de coleta de lixo, tem algumas conseqüências. Primeiro de tudo, qualquer string criada deve fazer sua própria cópia dos dados da string. O 'proprietário' dos dados da string deve ser mantido, porque quando o proprietário é deletado todas as referências se tornam inválidas. Se alguém tenta evitar o problema de referência ociosa tratando strings como tipos de valor, haverão muitos overheads de alocação de memória, cópia de dados, e desalocação de memória. Depois, a terminação em 0 implica que strings não podem se referir a outras strings. Dados da string no segmento de dados, pilha, etc., não podem se referir.Strings em D são tipos de referência, e a memória tem coleta de lixo automática. Isso significa que somente referências precisam ser copiadas, não os dados da string. Strings em D podem se referir a dados no segmento de dados estático, dados na pilha, dados dentro de outras strings, objetos, buffers de arquivos, etc. Não é necessário manter o 'proprietário' dos dados da string. A questão óbvia é se múltiplas strings em D se referem aos mesmos dados de string, o que acontece se os dados são modificados? Todas as referência irão apontar agora para os ados modificados. Isso pode ter suas próprias conseqüências, que podem ser evidades se a convenção de cópia-na-escrita for seguida. Tudo que cópia-na-escrita é é que se uma string é escrita, uma cópia atual dos dados da string é feita antes. O resultado de strings em D sendo somente referência e com coleta de lixo é que código que faz muitas manipulações de string, como um compressor lzw, pode ser muito mais eficiênte em termos de consumo de memória e velocidade. BenchmarkVamos dar uma olhada em um pequeno utilitário, conta-palavras, que conta a freqüência de cada palavra em um arquivo de texto. Em D, pareceria com isso:import file; Duas pessoas escreveram implementações em C++ usando a biblioteca padrão de gabaritos C++, wccpp1 e wccpp2. O arquivo de entrada alice30.txt é o texto de "Alice no País das Maravilhas." O compilador D, dmd, e o compilador C++, dmc, compartilham o mesmo otimizador e gerador de código, que provê uma comparação da eficiência da semântica das linguagens ao invés da sofisticação do gerador de código e otimização. Testes foram executados em uma máquina com Win XP. dmc usa STLport para a implementação de gabaritos.
Os seguintes testes foram executados no linux, novamente comparando um compilador D (gdc) e um compilador C++ (g++) que compartilham um otimizador e gerador de código comuns. O sistema é Pentium III 800MHz rodando RedHat Linux 8.0 e gcc 3.4.2. O compilador Digital Mars D para linux (dmd) é incluído para comparação.
Estes testes comparam gdc com g++ em um PowerMac G5 2x2.0GHz rodando MacOS X 10.3.5 e gcc 3.4.2. (Tempos são um pouco menos precisos.)
wccpp2 por Allan Odgaard#include <algorithm> |