|
0 / 0 / 0
Регистрация: 14.02.2016
Сообщений: 8
|
|||||||||||
Конструирование string из stringstream09.06.2018, 19:38. Показов 4146. Ответов 13
Я уже довольно долгое время ломаю голову над вот таким вопросом конструирования строки из stringstream
Такой код работает:
0
|
|||||||||||
| 09.06.2018, 19:38 | |
|
Ответы с готовыми решениями:
13
Stringstream C++ |
|
0 / 0 / 0
Регистрация: 14.02.2016
Сообщений: 8
|
|
| 10.06.2018, 07:49 [ТС] | |
|
Нет первый вариант работает и возвращает то, что нужно. Второй просто не работает. Я понимаю, что итераторы не особо корректны, т.к. Они итерируются по уже несуществующему объекту. Но тем не менее все указатели в норме и указывают в одни и те же места, хоть это и приведет к непредвиденным последствиям. Меня интересует именно проблема конструирования строки во втором варианте.
Добавлено через 1 минуту Если вы не верите в работоспособность, то попробуйте запустить этот код. Я пробовал и локально и в онлайн IDE
0
|
|
|
Комп_Оратор)
|
|||||||
| 10.06.2018, 22:38 | |||||||
|
http://www.cplusplus.com/refer... tream/str/ Добавлено через 31 минуту Нет не ссылку. В заголовочном sstream есть две перегрузки - одна void сеттер и другая геттер возвращающая копию строки из буффера (по сути str - обёртка над ним) :
1
|
|||||||
|
0 / 0 / 0
Регистрация: 14.02.2016
Сообщений: 8
|
|
| 10.06.2018, 23:47 [ТС] | |
|
Вы правы, что это не хорошо. Я с этим не спорю. Компилируется, т.к. у строки есть конструктор принимающий итераторы. В этом какрас и проблема. Оба случая компилируются, в обоих случаях передаются итераторы, которые указывают в одни и те же места. Но вот второй пример кода не работает вовсе. Первый работает в ide срр.sh, например. Локально gcc 6 версии с флагом std=c++14 компилируется и отрабатывает нормально только первый вариант.
Добавлено через 9 минут http://www.cplusplus.com/refer... ng/string/ Для строки есть конструктор с итераторами.
0
|
|
|
Комп_Оратор)
|
||||
| 11.06.2018, 00:14 | ||||
|
У меня более поздний для Win32 + CodeBlock компилирует но выдаёт некоректный результат.
0
|
||||
|
87 / 87 / 18
Регистрация: 11.06.2018
Сообщений: 302
|
|
| 11.06.2018, 00:39 | |
Сообщение было отмечено egorrich как решение
Решение
egorrich, господи, да что ж вы такое говорите!
Этот код не работает! Ни первый ни второй. Не работают они по-разному, но не работают оба! Почему? Потому что в первом варианте str() возвращает временный объект. Временный. Объект. Что это означает для вашего кода? Первое - это то, что строка, помещенная в этот временный, никуда не скопированный объект умирает в конце выражения (в строках 4 и 5), а взятие итератора для этой строки дает итератор, указывающий на уже освобожденную память. Второе - объектов у вас два! Вы два раза вызываете str() и два раза это два разных объекта строк. И вы не имеете права использовать эти разные итераторы от разных объектов как итераторы для одной последовательности.Итак, в первом коде две ошибки. Итераторы, указывающие на мертвую строку и итераторы указывающие на начало и конец разных объектов строк (даже если бы они были живы). Во втором коде объекты еще живы - т.к. выражение не закончено, но остается вторая ошибка - это разные объекты, пусть и идентичные по содержимому. Begin() от одного объекта, а End() от другого.Оба кода порождают неопределенное поведение (UB). Это означает, что нет никакого смысла рассуждать о видимой работоспособности этого кода, т.к. его работоспособность (или неработоспособность) проистекает из случайности. Вы не должны писать такой код. Он некорректен. Он будет показывать разный результат на разных компиляторах, он даже может по-разному работать от запуска к запуску. В зависимости, например, от размеров данных. Вердикт "поведение не определено" может проявляться как угодно, даже благоприятным образом, или наоборот, самым страшным. Просто не нужно писать такой код, и уж тем более не нужно рассуждать о причинах его работоспособности. Даже если вы исследуете конкретный код и причины, которые заставляют его работать ожидаемым для вас способом, это может измениться при следующей перекомпиляции, стоит лишь изменить опции, или даже просто добавить еще одну инструкцию. Вот посмотрите сюда: http://rextester.com/NNSYE86106 Это онлайн компилятор и здесь ваш второй нерабочий по вашим словам код работает. Это проявление UB. А теперь посмотрите сюда: http://rextester.com/JSXM73247. А здесь, наоборот, ваш первый, рабочий по вашим словам код, тем не менее не работает. Это тоже проявление UB. Не делайте так. Делайте правильно. Добавлено через 3 минуты IGPIGP, Пожалуйста, прекратите вводить ТС в заблуждение.
3
|
|
|
0 / 0 / 0
Регистрация: 14.02.2016
Сообщений: 8
|
|
| 11.06.2018, 01:07 [ТС] | |
|
При запуске второго варианта вываливается вот такая ошибка:
terminate called after throwing an instance of 'std::length_error' what(): basic_string::_S_create Error launching program (Aborted) Говорит, что длина строка превышает максимальную. Но итераторы указывают на нормальные адреса, так же как и в первом варианте. Но вот этого я и не понимаю, где же проблема. Вроде два одинаковых варианта, но работают по разному. Может все это зависит от конкретного компилятора и не нужно искать смысл в этом? Добавлено через 10 минут Большое спасибо за ответ. Вы не подумайте. Я изначально осознавал, что это неопределенное поведение. И нигде такой код не использую. Меня ввели в заблуждение указатели итераторов при отладке. Они указывали на одни и те же адреса, что переменная s1, что адрес, взятый напрямую от ss.str().begin(). Вот я и задался таким вопросом. Ведь все вроде одинаково. Я понял, что рассуждения о UB ни к чему хорошему не приведут и такое поведение может зависет, например, от моего компилятора. Я очень рад, что вы дали мне развернутый ответ. Спасибо.
0
|
|
|
87 / 87 / 18
Регистрация: 11.06.2018
Сообщений: 302
|
||||||
| 11.06.2018, 01:28 | ||||||
|
egorrich, теперь, когда вы поняли, что и тот и другой код некорректны, можно попытаться объяснить видимое поведение.
Смотрите:
В любом случае, по правилам языка С++ вы не имеете права использовать *p1 и *p2 после освобождения их памяти (что происходило в первом примере). И вы также не имеете права использовать p1 и p2 (даже если память еще наша) для представления одной последовательности (например std::string(p1, p2 + 10)) - это происходило в первом и втором примерах. Второй момент как раз приводит к ошибке length error, которую вы цитировали, т.к. расстояние между p1 и p2 + 10 может значительно превышать размер строки - это же разные последовательности. Если строка проверяет внутри этот инвариант, будет получена ошибка, наподобие процитированной вами.
0
|
||||||
|
Комп_Оратор)
|
||
| 11.06.2018, 07:42 | ||
|
Я и правда не нашёл ничего кроме 2-х методов показанных здесь: Конструирование string из stringstream При этом, я действительно не понимаю, как метод возвращающий строку по значению, может запустить её конструктор. Я бы предположил наличие третьей перегрузки метода, принимающей пару итераторов, но найти её не смог. Объектные файлы не просматривал. Может объясните, как оно вообще компилируется? Почему, вернее. Остальное из сказанного в наших ответах достаточно похоже. igorrr37, первым сказал, что оба варианта не работают. Вы пришли третьим.
0
|
||
|
87 / 87 / 18
Регистрация: 11.06.2018
Сообщений: 302
|
|||||||||||||||||||||||||
| 11.06.2018, 14:51 | |||||||||||||||||||||||||
Сообщение было отмечено egorrich как решение
РешениеДавайте я еще раз объясню в чем проблемы этого кода. str() возвращает копию буфера в виде std::string (в вашей цитате - __string_type - это и есть std::string, вернее std::basic_string<T>, где T - это char в случае std::stringstream). У std::string есть методы, которые возвращают итераторы - begin() и end(). В выражении std::string::iterator s1 = ss.str().begin(); функция str() возвращает std::string - временный объект. Этот временный объект используется для получения итератора на начало строки. Затем этот итератор копируется в s1. В конце выражения временный объект уничтожается, а итератор остается "висячим". Это первая ошибка.Во второй строке вызывается str() снова, где весь сценарий повторяется. Опять создается временный объект (не тот же самый, что в первый раз, но технически могущий использовать ту же самую память, по принципу, который я показал в предыдущем ответе - отсюда видимая работоспособность кода в некоторых случаях), мы получаем у него итератор на элемент, следующий за последним, итератор копируется в s2, временный объект умирает. Но итератор s2, который был получен, не имеет никакого отношения к последовательности, на которую указывает s1. Тем не менее, они оба используются для конструирования новой строки str1 посредством конструктора от двух итераторов (http://ru.cppreference.com/w/c... sic_string , #6 по ссылке). Это - вторая ошибка.Надеюсь, теперь понятно, что сам по себе str() не играет никакой роли в проявлении этих ошибок.Вот, для примера, корректный вариант написания оригинального кода ТС:
Пример на тему:
Не по теме:
Я не знаю, что еще тут можно добавить. Если что-то до сих пор не понятно, просто перечитайте все мои посты еще раз. Или прочитайте какие-нибудь книги, где описана эта ошибка.
1
|
|||||||||||||||||||||||||
|
1130 / 789 / 232
Регистрация: 12.04.2010
Сообщений: 2,012
|
||||||||
| 11.06.2018, 18:46 | ||||||||
1
|
||||||||
| 11.06.2018, 20:45 | |
|
0
|
|
|
0 / 0 / 0
Регистрация: 14.02.2016
Сообщений: 8
|
|
| 11.06.2018, 22:04 [ТС] | |
|
Всем большое спасибо за ответы. Ответ igorrr37 мне был понятен, только хотелось более развернутого и подробного пояснения. ablex еще раз большое спасибо за очень подробное описание проблемы. Alex5, я знаю, как получить нормальную строку из stringstream, в этой теме меня интересовал иной вопрос. Всем большое спасибо за ответы.
0
|
|
| 11.06.2018, 22:04 | |
|
Помогаю со студенческими работами здесь
14
Stringstream и оператор >>
С# stringstream Создайте класс Animal. Добавьте поля string Name, string Kind, string Areal, int Population Создайте класс Animal. Добавьте поля string Name, string Kind, string Areal, int Population Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма).
На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
|
Первый деплой
lagorue 16.01.2026
Не спеша развернул своё 1ое приложение в kubernetes.
А дальше мне интересно создать 1фронтэнд приложения и 2 бэкэнд приложения
развернуть 2 деплоя в кубере получится 2 сервиса и что-бы они. . .
|
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ *
Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам
Кирхгофа, решает её и находит:
токи, напряжения и их 1 и 2 производные при t = 0;. . .
|
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым.
Но восстановить их можно так.
Для этого понадобится консольная утилита. . .
|
|
Изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
|
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
|
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11
— это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
|
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11
Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
|