#cpp
Сразу оговорюсь, вопрос чисто теоретический, без практического применения. 3 примера кода: 1) std::string s = "abc"; char& c = s[0]; c = 'A'; // OK, s == "Abc" 2) std::string s = "abc"; char& c = s[0]; s += "def"; c = 'A'; // Error: UB, s+="def" 'kill' c reference 3) std::string s = "abc"; s.reserve(100); char& c = s[0]; s += "def"; c = 'A'; // ??? OK (s == "Abcdef") or UB??? Цитата из Джосаттиса "Стандартная библиотека С++. Справочное руководство": Для того, чтобы избежать ошибок ..., следует зарезервировать достаточную емкость до того, как будет инициализирована ссылка... Собственно, вопрос, с точки зрения стандарта С++ 11 3-й пример кода корректен? (с точки зрения стиля - плохо, я понимаю).
Ответы
Ответ 1
Согласно п.21.3.1.1/4 черновика Стандарта вызов не-const функции-члена кроме operator[], at, front, back, begin, rbegin, end и rend может приводить к инвалидации ссыллок/указателей/итераторов на объекты строки (символы). В данном случае вызывается модифицирующий operator+=. Т.о. инвалидация (и как следствие - UB) возможна несмотря на присутствие вызова reserve.Ответ 2
А почему он должен быть некорректен? Вопрос нужно ставить по-другому: почему во втором случае случается UB. А случается оно потому, что буфер, на символ в котором указывает ссылка c, при расширении строки может быть уничтожен. В третьем же случае буфер остаётся прежним (по крайней мере до тех пор, пока новая длина строки не превышает его размеров).Ответ 3
Второй и третий случай абсолютно равнозначны, с точки зрения стандарта,— оба они могут породить UB. С практической точки зрения, ни один из этих случаев к UB не приведёт, ни на одной из популярных реализаций стандартной библиотеки.Ответ 4
std::string s = "abc"; // s.reserve(100); char& c = s[0]; for(;s[0] == c;) { s += "def"; ++c; cout << s << endl; } Этот код (и код с раскоментаренной строкой reserve) ясно показывает, что в первом случае неприятности наступают гораздо раньше. Но, в зависимости от того, какой именно объем выделяется строке изначально - может быть и наоборот. Но, как мне представляется (нет под рукой стандарта), третий код все же корректен, в то время как второй - нет.
Комментариев нет:
Отправить комментарий