Почему C++ не повторно реализует стандартные функции C с элементами/стилем C++?

Я просто слушал Подкаст от Scott Hanselman этим утром, где он говорит об интернационализации, особенно действительно хитрые вещи, как турецкий язык (с, он четыре, я), и тайский язык. Кроме того, Jeff Atwood имел сообщение :

9
задан greatwolf 19 December 2013 в 03:38
поделиться

10 ответов

Another more general question is why do not STL reimplementate all the standard C libraries

Because the old C libraries do the trick. The C++ standard library only re-implements existing functionality if they can do it significantly better than the old version. And for some parts of the C library, the benefit of writing new C++-implementations just isn't big enough to justify the extra standardization work.

As for atoi and the like, there are new versions of these in the C++ standard library, in the std::stringstream class.

To convert from a type T to a type U:

T in;
U out;
std::stringstream sstr(in);
sstr >> out;

As with the rest of the IOStream library, it's not perfect, it's pretty verbose, it's impressively slow and so on, but it works, and usually it is good enough. It can handle integers of all sizes, floating-point values, C and C++ strings and any other object which defines the operator <<.

EDIT:In addition,I have heard many other libraries avaliable for C++ make a lot of enhancement and extensions to STL.So does there libraries support these functions?

Boost has a boost::lexical_cast which wraps std::stringstream. With that function, you can write the above as:

U out = boost::lexical_cast<U>(in);
14
ответ дан 4 December 2019 в 06:35
поделиться

Даже в C, использование atoi не очень хорошо для преобразования пользовательского ввода. Он вообще не обеспечивает проверку ошибок. Предоставление его версии на C ++ не так уж и полезно - учитывая, что он ничего не будет бросать и делать, вы можете просто передать ему .c_str () и использовать его.

Вместо этого вы должны использовать strtol в коде C, который выполняет проверку ошибок. В C ++ 03 вы можете использовать строковые потоки, чтобы делать то же самое, но их использование чревато ошибками: что именно вам нужно проверить? .bad () , .fail () или .eof () ? Как вы съедаете оставшиеся пробелы? А как насчет флагов форматирования? Такие вопросы не должны беспокоить обычного пользователя, который просто хочет преобразовать свою строку. boost :: lexical_cast неплохо справляется, но, кстати, длинный столб (const string & str, size_t * idx = 0, int base = 10); беззнаковый длинный stoul (const string & str, size_t * idx = 0, int base = 10); long long stoll (const string & str, size_t * idx = 0, int base = 10); unsigned long long stoull (const string & str, size_t * idx = 0, int base = 10);

Эффекты : первые две функции вызывают strtol (str.c_str (), ptr, base) , а последние три функции вызовите strtoul (str.c_str (), ptr, base) , strtoll (str.c_str (), ptr, base) и strtoull (str.c_str () , ptr, base) соответственно. Каждая функция возвращает преобразованный результат, если таковой имеется. Аргумент ptr обозначает указатель на объект, внутренний по отношению к функции, который используется для определения того, что хранить в * idx . Если функция не вызывает исключение и idx! = 0 , функция сохраняет в * idx индекс первого неконвертированного элемента str.

Возвращает : преобразованный результат.

Выдает : invalid_argument if strtol , strtoul , strtoll или strtoull сообщает, что преобразование не может быть выполнено. Выбрасывает out_of_range , если преобразованное значение выходит за пределы диапазона представимых значений для возвращаемого типа.

7
ответ дан 4 December 2019 в 06:35
поделиться

Я вижу, что предлагаются решения, использующие std :: stringstream или std :: istringstream . Это может быть совершенно нормально для однопоточных приложений, но если приложение имеет много потоков и часто вызывает atoi (const std :: string & str) , реализованный таким образом, что приведет к снижению производительности.

Прочтите это обсуждение, например: http://gcc.gnu.org/ml/gcc-bugs/2009-05/msg00798.html . И посмотрите обратную трассировку конструктора std :: istringstream:

#0  0x200000007eb77810:0 in pthread_mutex_unlock+0x10 ()
   from /usr/lib/hpux32/libc.so.1
#1  0x200000007ef22590 in std::locale::locale (this=0x7fffeee8)
    at gthr-default.h:704
#2  0x200000007ef29500 in std::ios_base::ios_base (this=<not available>)
    at /tmp/gcc-4.3.1.tar.gz/gcc-4.3.1/libstdc++-v3/src/ios.cc:83
#3  0x200000007ee8cd70 in std::basic_istringstream<char,std::char_traits<char>,std::allocator<char> >::basic_istringstream (this=0x7fffee4c,
    __str=@0x7fffee44, __mode=_S_in) at basic_ios.h:456
#4  0x4000f70:0 in main () at main.cpp:7

Итак, каждый раз, когда вы вводите atoi () и создаете локальный варибал типа std :: stringstream , вы блокируете глобальный мьютекс и в многопоточное приложение, скорее всего, приведет к ожиданию этого мьютекса.

Итак, в многопоточном приложении лучше не использовать std :: stringstream . Например, просто вызовите atoi (const char *) :

inline int atoi(const std::string& str)
{
    return atoi(str.c_str());
}
4
ответ дан 4 December 2019 в 06:35
поделиться

For your example, you've got two options:

std::string mystring("4");
int myint = atoi(mystring.c_str());

Or something like:

std::string mystring("4");
std::istringstream buffer(mystring);
int myint = 0;
buffer >> myint;

The second option gives you better error management than the first.

3
ответ дан 4 December 2019 в 06:35
поделиться

You can write a more generic string to number convert as such:

template <class T>
T strToNum(const std::string &inputString,
           std::ios_base &(*f)(std::ios_base&) = std::dec)
{
    T t;
    std::istringstream stringStream(inputString);

    if ((stringStream >> f >> t).fail())
    {
        throw runtime_error("Invalid conversion");
    }
    return t;
}


// Example usage
unsigned long ulongValue = strToNum<unsigned long>(strValue);
int intValue             = strToNum<int>(strValue);

int intValueFromHex      = strToNum<int>(strHexValue,std::hex);
unsigned long ulOctValue = strToNum<unsigned long>(strOctVal, std::oct);
1
ответ дан 4 December 2019 в 06:35
поделиться

Потому что старые библиотеки C по-прежнему работают со стандартными типами C ++ с очень небольшой адаптацией. Вы можете легко изменить const char * на std :: string с помощью конструктора и вернуть обратно с помощью std :: string :: c_str () . В вашем примере с std :: string s просто вызовите atoi (s.c_str ()) , и все в порядке. Пока вы можете легко переключаться вперед и назад, нет необходимости добавлять новые функции.

Я не придумываю функции C, которые работают с массивами, а не с классами контейнеров, за исключением таких вещей, как qsort () и bsearch () , а в STL есть более эффективные способы делать такие вещи. Если бы у вас были конкретные примеры, я мог бы их рассмотреть.

C ++ действительно должен поддерживать старые библиотеки C в целях совместимости, но тенденция состоит в том, чтобы предоставлять новые методы там, где это оправдано, и предоставлять интерфейсы для старых функций, когда особых улучшений не наблюдается. Например, Boost lexical_cast является улучшением по сравнению с такими функциями, как atoi () и strtol () , так же как стандартная строка C ++ является улучшением по сравнению с C способ делать вещи. (Иногда это субъективно. Хотя потоки C ++ имеют значительные преимущества по сравнению с функциями CI / O, бывают случаи, когда я предпочел бы вернуться к способу работы с C. Некоторые части стандартной библиотеки C ++ превосходны, а некоторые части, ну нет.)

Boost lexical_cast является улучшением по сравнению с такими функциями, как atoi () и strtol () , так же как стандартная строка C ++ является улучшением по сравнению со способом C делать вещи. (Иногда это субъективно. Хотя потоки C ++ имеют значительные преимущества по сравнению с функциями CI / O, бывают случаи, когда я предпочел бы вернуться к способу работы с C. Некоторые части стандартной библиотеки C ++ превосходны, а некоторые части, ну нет.)

Boost lexical_cast является улучшением по сравнению с такими функциями, как atoi () и strtol () , так же как стандартная строка C ++ является улучшением по сравнению со способом C делать вещи. (Иногда это субъективно. Хотя потоки C ++ имеют значительные преимущества по сравнению с функциями CI / O, бывают случаи, когда я предпочел бы вернуться к способу работы с C. Некоторые части стандартной библиотеки C ++ превосходны, а некоторые части, ну нет.)

1
ответ дан 4 December 2019 в 06:35
поделиться

Для преобразований я считаю наиболее простым использовать boost lexical_cast (за исключением того, что он может быть тоже , строго проверяющим правильность преобразований строки в другие типы) .

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

1
ответ дан 4 December 2019 в 06:35
поделиться

Есть всевозможные способы разбора числа из строки, atoi можно легко использовать с std: : строка через atoi (std.c_str ()) , если вы действительно хотите, но atoi имеет плохой интерфейс, потому что нет надежного способа определить, произошла ли ошибка во время парсинг.

Здесь ' s еще один немного более современный способ C ++ получить int из std :: string :

std::istringstream tmpstream(str);
if (tmpstream >> intvar)
{
    // ... success! ...
}
0
ответ дан 4 December 2019 в 06:35
поделиться

The tongue in cheek answer is: Because STL is a half-hearted attempt to show how powerful C++ templates could be. Before they got to each corner of the problem space, time was up.

There are two reasons: Creating an API takes time and effort. Create a good API takes a lot of time and a huge effort. Creating a great API takes an insane amount of time and an incredible effort. When the STL was created, OO was still pretty new to the C++ people. They didn't have the ideas how to make fluent and simple API. Today, we think iterators are so 1990 but at the time, people thought "Bloody hell, why would I need that? for (int i=0; i<...) has been good enough for three decades!"

So STL didn't became the great, fluent API. This isn't all C++ fault because you can make good APIs with C++. But it was the first attempt to do that and it shows. Before the API could mature, it was turned into a standard and all the ugly shortcomings were set into stone. And on top of this, there was all this legacy code and all the libraries which already could do everything, so the pressure wasn't really there.

To solve your misery, give up on STL and have a look at the successors: Try boost and maybe Qt. Yeah, Qt is a UI library but it also has a pretty good standard library.

0
ответ дан 4 December 2019 в 06:35
поделиться

Нет хорошего способа узнать, что атой не работает. Он всегда возвращает целое число. Это целое число допустимое преобразование? Или 0, -1 или что-то еще указывает на ошибку? Да, это может вызвать исключение, но это изменит исходный контракт, и вам придется обновить весь свой код, чтобы перехватить исключение (на что жалуется OP).

Если перевод занимает слишком много времени, напишите свой собственный atoi:

int atoi(const std::string& str)
{
    std::istringstream stream(str);
    int ret = 0;
    stream >> ret;
    return ret;
}
5
ответ дан 4 December 2019 в 06:35
поделиться