Форум » C/C++ » Явное противоречие в Стандарте C++ в описании контейнера std::string » Ответить

Явное противоречие в Стандарте C++ в описании контейнера std::string

Сыроежка: Ракссмотрим простой пример. [pre2]const int N = 5; int a[N] = { 1, 2, 3, 4, 5 }; for ( int i = 0; i < N; i++ ) std::cout << a << std::endl;[/pre2] В описании индексного оператора в стандарту C++ записано, что [quote]E1[E2] is identical (by definition) to *((E1)+(E2))[/quote] Возвращаясь к примеру цикла, его можно переписать следующим образом [quote]for ( int *p = a; p != a + N; ++p ) std::cout << *p << std::endl;[/quote] Эти две записи одного и того же цикла эквивалентны. Теперь обратимся к описанию индексного оператора для стандартного класса std::string в стандарте C++. [quote]const_reference operator[](size_type pos) const; reference operator[](size_type pos); 1 Requires: pos <= size(). 2 Returns: *(begin() + pos) if pos < size(). Otherwise, returns a reference to an object of type charT with value charT(), where modifying the object leads to undefined behavior. 3 Throws: Nothing. 4 Complexity: constant time.[/quote] Из этого описания следует, что вы можетте обращаться к элементу объекта типа std::string следующим образом: [pre2]std::string s( /* some string literal */ ); s[s.size()];[/pre2] Или если строка пустая, то [pre2]std::string s; s[0];[/pre2] Более того вы можете написать следующий код [pre2]char *p = s.data(); while ( *p ) ++p;[/pre2] То есть вы можетте обращаться к элементу s.data() + s.size() или *( &s[0] + s.size() ), хотя не можете (то есть стандартом не разрешается) изменять этот элемент. То есть согласно стандарту C++ 2011 завершающий символ '\0' теперь является частью хранимой в классе std::string строки. К тому же никто не запрещает итератор класса std::string определить просто как char * Итак, вы можете записать [pre2]for ( char *p = &s[0]; *p; ++p ) { /* ... */ }[/pre2] и в то же самое время вы не можете так записать если итератором является char * [pre2]for ( std::string::iterator p = s.begin(); *p; ++p ) { /* ... */ }[/pre2] Хотя эти записи полностью эквивалентны, если итератор в классе std:;string определен как char * Действительно, мы можем переписать цикл [pre2]for ( char *p = &s[0]; *p; ++p ) { /* ... */ }[/pre2] в виде [pre2]for (auto p = s.begin(); *p; ++p ) { /* ... */ }[/pre2] Чем является p в этом цикле? С одной стороны, это std::string::iterator, с другой стороны, это char * Получается, что стандарт заявляет, что данное предложение [pre2]for ( char *p = &s[0]; *p; ++p ) { /* ... */ }[/pre2] корректное, и в то же самое время он заявляет, что данное предложение некорректное, так как никто нам не запрещает определеить std::string::iterator! как char *! Я написал об этом очевидном на мой взгляд противоречии стандарта на форуме по обсуждению стандарта C++. Но, похоже, до членов комитета по стандартизации С++ это доходит со скрипом!

Ответов - 1

Сыроежка: Фактически, получается, что стандард C++ говорит, что следующий код [pre2]std::string s( /* some string literal */ ); for ( char *p = &s[0]; *p; ++p ) { /* ... */ }[/pre2] является корректным кодом, в то время как этот код [pre2]std::string s( /* some string literal */ ); typedef char *iterator; for ( iterator p = &s[0]; *p; ++p ) { /* ... */ }[/pre2] является некорректным кодом, то есть неразрешенным стандартом.



полная версия страницы