Por que as classes std::fstream não aceitam std::string?
Pergunta
Na verdade, esta não é uma questão de design, embora possa parecer.(Bem, ok, é uma questão de design).O que estou me perguntando é por que o C++ std::fstream
as aulas não demoram std::string
em seu construtor ou métodos abertos.Todo mundo adora exemplos de código, então:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::string filename = "testfile";
std::ifstream fin;
fin.open(filename.c_str()); // Works just fine.
fin.close();
//fin.open(filename); // Error: no such method.
//fin.close();
}
Isso me incomoda o tempo todo quando trabalho com arquivos.Certamente a biblioteca C++ usaria std::string
qualquer lugar possível?
Solução
Pegando uma string C, o C++03 std::fstream
classe reduziu a dependência do std::string
aula.No C++ 11, no entanto, o std::fstream
classe permite passar um std::string
para seu parâmetro construtor.
Agora, você pode se perguntar por que não existe uma conversão transparente de um std:string
para uma string C, então uma classe que espera uma string C ainda pode levar um std::string
assim como uma classe que espera um std::string
pode pegar uma string C.
A razão é que isso causaria um ciclo de conversão, que por sua vez poderia levar a problemas.Por exemplo, suponha std::string
seria conversível em uma string C para que você pudesse usar std::string
está com fstream
S.Suponha também que a string C seja conversível em std::string
s como é o estado no padrão atual.Agora, considere o seguinte:
void f(std::string str1, std::string str2);
void f(char* cstr1, char* cstr2);
void g()
{
char* cstr = "abc";
std::string str = "def";
f(cstr, str); // ERROR: ambiguous
}
Porque você pode converter de qualquer maneira entre um std::string
e uma string C a chamada para f()
poderia resolver qualquer um dos dois f()
alternativas e, portanto, é ambígua.A solução é quebrar o ciclo de conversão tornando explícita uma direção de conversão, que é o que o STL escolheu fazer com c_str()
.
Outras dicas
Existem vários locais onde o comitê do padrão C++ não otimizou realmente a interação entre recursos na biblioteca padrão.
std::string
e seu uso na biblioteca é um deles.
Um outro exemplo é std::swap
.Muitos contêineres têm uma função de membro swap, mas nenhuma sobrecarga de std::swap é fornecida.O mesmo vale para std::sort
.
Espero que todas essas pequenas coisas sejam corrigidas no próximo padrão.
Talvez seja um consolo:todos os fstream obtiveram um open(string const &, ...) próximo ao open(char const *, ...) no rascunho de trabalho do padrão C++0x.(ver, por exemplo27.8.1.6 para a declaração basic_ifstream)
Então, quando for finalizado e implementado, você não vai mais pegar :)
A biblioteca stream IO foi adicionada à biblioteca C++ padrão antes do STL.Para não quebrar a compatibilidade com versões anteriores, foi decidido evitar a modificação da biblioteca IO quando o STL foi adicionado, mesmo que isso significasse alguns problemas como o que você levantou.
@ Bernardo:
Monólitos "não formaram". "Tudo para um e um para todos" pode funcionar para os mosqueteiros, mas não funciona tão bem para os designers de classe.Aqui está um exemplo que não é totalmente exemplar e ilustra o quanto você pode errar quando o design se transforma em overdesign.O exemplo, infelizmente, foi retirado de uma biblioteca padrão perto de você...~ http://www.gotw.ca/gotw/084.htm
É inconsequente, isso é verdade.O que você quer dizer com a interface do std::string sendo grande?O que significa grande, neste contexto - muitas chamadas de método?Não estou sendo jocoso, estou realmente interessado.
Ela tem mais métodos do que realmente precisa, e seu comportamento de usar deslocamentos integrais em vez de iteradores é um pouco duvidoso (pois é contrário ao modo como o resto da biblioteca funciona).
O verdadeiro problema, creio, é que a biblioteca C++ tem três partes;possui a antiga biblioteca C, possui o STL e possui strings e iostreams.Embora alguns esforços tenham sido feitos para unir as diferentes partes (por ex.a adição de sobrecargas à biblioteca C, porque C++ suporta sobrecarga;a adição de iteradores a basic_string;a adição dos adaptadores do iterador iostream), há muitas inconsistências quando você olha os detalhes.
Por exemplo, basic_string inclui métodos que são duplicatas desnecessárias de algoritmos padrão;os vários métodos find, provavelmente poderiam ser removidos com segurança.Outro exemplo:localidades usam ponteiros brutos em vez de iteradores.
C++ cresceu em máquinas menores do que os monstros para os quais escrevemos código hoje.Na época em que o iostream era novo, muitos desenvolvedores realmente se importavam com o tamanho do código (eles tinham que ajustar todo o programa e dados em várias centenas de KB).Portanto, muitos não queriam usar a "grande" biblioteca de strings C++.Muitos nem usaram a biblioteca iostream pelos mesmos motivos, tamanho do código.
Não tínhamos milhares de megabytes de RAM para distribuir como temos hoje.Normalmente não tínhamos vinculação em nível de função, então estávamos à mercê do desenvolvedor da biblioteca para usar muitos arquivos de objetos separados ou então extrair toneladas de código desnecessário.Todo esse FUD fez com que os desenvolvedores se afastassem do std::string.
Naquela época eu evitava std::string também."Muito inchado", "chamado de malloc com muita frequência", etc.Tolamente usando buffers baseados em pilha para strings e depois adicionando todos os tipos de código tedioso para garantir que ele não seja excedido.
Existe alguma classe em STL que receba uma string ...Acho que não (não consegui encontrar nenhum na minha pesquisa rápida).Portanto, provavelmente é uma decisão de design que nenhuma classe em STL deva depender de qualquer outra classe STL (que não seja diretamente necessária para funcionalidade).
Acredito que isso foi pensado e feito para evitar a dependência;ou seja#include <fstream> não deve forçar #include <string>.
Para ser honesto, esta parece ser uma questão bastante inconsequente.Uma pergunta melhor seria: por que a interface do std::string é tão grande?
Hoje em dia você pode resolver esse problema com muita facilidade:adicionar -std=c++11
para o seu CFLAGS
.