2008-08-28 12 views
34

Это не вопрос дизайна, действительно, хотя это может показаться. (Ну, ладно, это вопрос дизайна). Мне интересно, почему классы C++ std::fstream не принимают std::string в свой конструктор или открывают методы. Все любят примеры кода:Почему классы std :: fstream не принимают std :: string?

#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(); 
} 

Это позволяет мне работать с файлами постоянно. Разумеется, библиотека C++ будет использовать std::string везде, где это возможно?

ответ

26

Сняв строку C, уменьшите зависимость класса C++ 03 std::fstream от класса std::string. Однако в C++ 11 класс std::fstream позволяет передавать std::string для своего параметра конструктора.

Теперь, вы можете удивиться, почему не существует прозрачное преобразование из std:string в строку C, так что класс, который ожидает, что строка C может еще взять std::string так же, как класс, ожидающий std::string может занять C строка.

Причина в том, что это приведет к циклу преобразования, что, в свою очередь, может привести к проблемам. Например, предположим, что std::string будет конвертируемым в строку C, чтобы вы могли использовать std::string с с fstream с. Предположим также, что строка C преобразуется в std::string s, как и состояние в текущем стандарте. Теперь рассмотрим следующее:

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 
} 

Потому что вы можете преобразовать любой путь между std::string и строки C вызов f() может решить ни к одному из двух f() альтернатив, и, таким образом неоднозначно. Решение состоит в том, чтобы разбить цикл конверсии, сделав одно направление преобразования явным, и это то, что STL выбрала для c_str().

+1

Образец не должен вызывать каких-либо двусмысленностей с правилами разрешения перегрузки. `f (char *, std :: string)` является [точное совпадение] (http://www.lcdf.org/c++/clause13.html#s13.3.3.1.1), в то время как другие потребуют преобразования, следовательно, первая была бы лучшей жизнеспособной функцией.Если вы удалили первый «f», тогда как «(char * &, std :: string &) -> (char *, std :: string) -> (char *, char *)" является [лучшей последовательностью преобразования ] (http://www.lcdf.org/c++/clause13.html#s13.3.3), чем "(char * &, std :: string &) -> (char *, std :: string) -> (std: : string, char *) ", вторая` f` будет лучшей жизнеспособной функцией. Я что-то упускаю? – outis 2010-11-14 23:49:43

0

Есть ли какой-либо класс в STL, который берет строку ... Я не думаю, что так (не смог найти ни одного в моем быстром поиске). Таким образом, это, вероятно, какое-то дизайнерское решение, что ни один класс в STL не должен зависеть от какого-либо другого класса STL (который не нужен непосредственно для функциональности).

14

Существует несколько мест, где стандартный комитет C++ не действительно оптимизирует взаимодействие между объектами в стандартной библиотеке.

std::string и его использование в библиотеке является одним из них.

Другой пример: std::swap. Многие контейнеры имеют функцию подкачки, но перегрузка std :: swap не предоставляется. То же самое касается std::sort.

Надеюсь, все эти мелочи будут исправлены в предстоящем стандарте.

0

Я считаю, что об этом задумано и сделано, чтобы избежать зависимости; то есть #include <fstream> не следует принудительно использовать для #include <string>.

Если честно, это кажется совершенно несущественной проблемой. Лучший вопрос: почему интерфейс std :: string настолько велик?

2

Это несущественно, это правда. Что вы подразумеваете под большим интерфейсом std :: string? Что означает большое значение, в этом контексте - много вызовов методов? Я не увлекаюсь, меня действительно интересует.

У этого есть больше методов, чем это действительно нужно, и его поведение использования интегральных смещений, а не итераторов, немного немного (так как это противоречит тому, как работает остальная часть библиотеки).

Настоящая проблема, я думаю, состоит в том, что библиотека C++ состоит из трех частей; у него есть старая библиотека C, у нее есть STL, и у нее есть строки и iostreams. Несмотря на то, что были предприняты некоторые усилия для объединения различных частей (например, добавление перегрузок в библиотеку C, поскольку C++ поддерживает перегрузку, добавление итераторов в basic_string, добавление адаптеров итератора iostream), существует много несоответствий, когда вы посмотрите на детали.

Например, basic_string включает методы, которые являются ненужными дубликатами стандартных алгоритмов; различные методы поиска, возможно, можно было бы безопасно удалить. Другой пример: локали используют вместо них итераторы raw-указатели.

3

@ Bernard:
Монолиты "Unstrung." «Все для одного и для всех» могут работать для мушкетеров, но это не так хорошо работает для классных дизайнеров. Вот пример, который не является вполне образцовым, и он показывает, насколько сильно вы можете ошибиться, когда дизайн превращается в overdesign. Пример, к сожалению, взятый из стандартной библиотеки рядом с вами ... ~ http://www.gotw.ca/gotw/084.htm

11

Может быть, это утешение: все fstream-х получили открытую (строка сопзЬ & ...) рядом с открытым (полукокса сопзЬ *, ...) в рабочем проекте стандарта C++ 0x. (смотрите, например, 27.8.1.6 для объявления basic_ifstream)

Так что, когда он получает доработан и реализован, он не получит больше тебя :)

9

Библиотека IO была добавлена ​​к стандартной библиотеке C++, прежде чем поток STL. Чтобы не нарушать обратную совместимость, было принято решение не модифицировать библиотеку ввода-вывода при добавлении STL, даже если это означало некоторые проблемы, подобные тем, которые вы поднимаете.

1

C++ вырос на более мелких машинах, чем у монстров, на которых мы пишем код на сегодня. Назад, когда iostream был новым, многие разработчики действительно заботились о размере кода (они должны были вместить всю свою программу и данные в несколько сотен КБ). Поэтому многие не хотели втягивать «большую» библиотеку строк C++. Многие даже не использовали библиотеку iostream по тем же причинам, размер кода.

У нас не было тысяч мегабайт ОЗУ, чтобы выбраться так же, как сегодня. У нас обычно не было связей уровня функции, поэтому мы были во власти разработчика библиотеки, чтобы использовать множество отдельных объектных файлов или тянуть тонны невостребованного кода. Все это FUD заставило разработчиков уклониться от std :: string.

В то время я избегал std :: string тоже. «Слишком раздутый», «слишком часто называемый malloc» и т. Д. Глупо использовать стековые буферы для строк, а затем добавлять все виды утомительного кода, чтобы убедиться, что он не переполняется.

0

В настоящее время вы можете решить эту проблему очень легко: добавьте -std=c++11 к вашему CFLAGS.

 Смежные вопросы

  • Нет связанных вопросов^_^