Espero que você perceba que tudo isso é profundamente definido pela implementação, tanto para Java quanto para C ++. Dito isto, o modelo de objetos de Java requer bastante espaço.
Objetos C ++ não (geralmente) precisam qualquer armazenamento, exceto o que os membros precisam. Observe que (diferente do Java, onde tudo o que é definido pelo usuário é um tipo de referência), o código do cliente pode usar objetos como tipo de valor ou como tipos de referência, ou seja, um objeto pode armazenar um ponteiro / referência para outro objeto ou armazenar diretamente o objeto sem indireção. Um ponteiro adicional por objeto é necessário se houver algum virtual
método, mas várias classes úteis são projetadas para se dar bem sem polimorfismo e não precisam disso. Não há metadados do GC nem bloqueio por objeto. Assim, os class IntWrapper { int x; public: IntWrapper(int); ... };
objetos não precisam de mais espaço do que o plain int
s e podem ser colocados diretamente (ou seja, sem direcionamento) em coleções e outros objetos.
Matrizes são complicadas simplesmente porque não existe um equivalente comum pré-fabricado a uma Matriz Java em C ++. Você pode simplesmente alocar um monte de objetos com new[]
(sem custos indiretos / metadados), mas não há campo de comprimento - a implementação provavelmente armazena um, mas você não pode acessá-lo. std::vector
é uma matriz dinâmica e, portanto, possui sobrecarga adicional e uma interface maior. std::array
e matrizes no estilo C (int arr[N];
), precisa de uma constante em tempo de compilação. Em teoria, deve ser apenas o armazenamento do objeto mais um único número inteiro para o comprimento - mas como você pode obter redimensionamento dinâmico e uma interface completa com muito pouco espaço extra, basta fazer isso na prática. Observe que todas essas, assim como todas as outras coleções, assumem o padrão de armazenar os objetos por valor, economizando indiretamente o espaço e as referências, além de melhorar o comportamento do cache. Você deve armazenar explicitamente ponteiros (inteligentes, por favor) para obter indireção.
As comparações acima não são inteiramente justas, porque algumas dessas economias são proporcionadas pela não inclusão de recursos que o Java inclui e seu equivalente em C ++ geralmente é menos otimizado do que o equivalente em Java (*). A maneira comum de implementar virtual
em C ++ impõe exatamente tanta sobrecarga quanto a maneira comum de implementar virtual
em Java. Para obter um bloqueio, você precisa de um objeto mutex com todos os recursos, que provavelmente é maior que alguns bits. Para obter a contagem de referência ( nãoequivalente ao GC e não deve ser usado como tal, mas às vezes útil), você precisa de um ponteiro inteligente que adicione um campo de contagem de referência. A menos que o objeto seja construído com cuidado, a contagem de referência, o objeto ponteiro inteligente e o objeto referenciado estejam em locais completamente separados, e mesmo quando você o constrói da maneira correta, o ponteiro compartilhado pode (deve?) Ainda ser dois ponteiros em vez de um. Por outro lado, o bom estilo C ++ não usa esses recursos o suficiente para importar - na prática, os objetos de uma biblioteca C ++ bem escrita usam menos. Isso não significa necessariamente menos uso geral de memória, mas significa que o C ++ tem uma boa vantagem nesse sentido.
(*) Por exemplo, você pode receber chamadas virtuais, códigos de hash de identidade e bloquear com apenas uma palavra para alguns objetos (e duas palavras para muitos outros objetos) mesclando as informações de tipo com vários sinalizadores e removendo os bits de bloqueio dos objetos que estão improvável que precise de bloqueios. Consulte Implementação com eficiência de espaço e tempo do Java Object Model (PDF) de David F. Bacon, Stephen J. Fink e David Grove para obter uma explicação detalhada dessa e de outras otimizações.
int
? Nesse caso, você deve compará-lo comint
Java, nãoInteger
- desde que suas entradas C ++ sejam 32 bits.