Страницы

Поиск по вопросам

воскресенье, 8 декабря 2019 г.

Ссылка на символ в строке и изменение строки

#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) ясно показывает, что в первом случае неприятности наступают гораздо раньше. Но, в зависимости от того, какой именно объем выделяется строке изначально - может быть и наоборот. Но, как мне представляется (нет под рукой стандарта), третий код все же корректен, в то время как второй - нет.

Комментариев нет:

Отправить комментарий