Форум программистов, компьютерный форум CyberForum.ru

std::string в char* - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 94, средняя оценка - 4.91
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
11.06.2012, 14:13     std::string в char* #1
Можно ли привести std::string к указателю на нуль-терминальную строку? Как?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.06.2012, 14:17     std::string в char* #2
string::c_str()
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
11.06.2012, 14:50  [ТС]     std::string в char* #3
Думаешь, я не могу этого сам написать? Я имел ввиду готовый член. Он существует?
Bers
Заблокирован
11.06.2012, 14:56     std::string в char* #4
Цитата Сообщение от taras atavin Посмотреть сообщение
Можно ли привести std::string к указателю на нуль-терминальную строку? Как?
Нельзя.

Но можно сделать эквивалентную по смыслу операцию:

C++
1
2
3
4
5
6
7
8
9
int main()
{
    std::string test("trololo");
 
    char* ptr = &test[0]; //получаем указатель на первый символ си-строчки
 
    std::cout<<ptr<<std::endl;
    return 0;
}
Но крайне не рекомендуется. Ибо нет никакой гарантии, что внутреннее хранилище стринга является непрерывным блоком памяти.
(разные реализации стандартной библиотеки могут по разному реализовывать std::string)

Безопасным способом является получение си-строки через метод: string::c_str()
Однако, данный метод обязан вернуть указатель на си-строку эквивалентную тому значению, что хранит в себе сам стринг. Это означает, что если стринг хранит данные не в непрерывном блоке памяти, то ему придётся выполнить ряд действий по созданию такого непрерывного блока памяти, чтобы предоставить указатель на него наружу, что приведет к падению производительности.

Если нужно гарантировать возможность быстрой работы, то можно использовать std::vector<char>, который исходя из ряда требований к контейнеру всегда хранит данные в непрерывном блоке памяти. И тогда запись:

C++
1
char* ptr = &test[0];
гарантированно будет валидна.
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
11.06.2012, 15:00  [ТС]     std::string в char* #5
Цитата Сообщение от Bers Посмотреть сообщение
Безопасным способом является получение си-строки через метод: string::c_str()
Однако, данный метод обязан вернуть указатель на си-строку эквивалентную тому значению, что хранит в себе сам стринг. Это означает, что если стринг хранит данные не в непрерывном блоке памяти, то ему придётся выполнить ряд действий по созданию такого непрерывного блока памяти, что предоставить указатель на него наружу, что приведет к падению производительности.
Это разовая операция с достаточно короткой строкой, менее сотни символов, а времени на неё не жалко двух секунд. Требуется ли освобождать указатель, который вернёт string::c_str()?
Bers
Заблокирован
11.06.2012, 15:01     std::string в char* #6
Цитата Сообщение от taras atavin Посмотреть сообщение
Думаешь, я не могу этого сам написать? Я имел ввиду готовый член. Он существует?
Можно унаследоваться от std::string и определить свой собственный operator char*()
И тогда приведение будет доступно без явного вызова c_str()

Добавлено через 41 секунду
Цитата Сообщение от taras atavin Посмотреть сообщение
Это разовая операция с достаточно короткой строкой, менее сотни символов, а времени на неё не жалко двух секунд. Требуется ли освобождать указатель, который вернёт string::c_str()?
Ни в коем случае. Данные являются собственностью стринга, а не вызывающей стороны.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.06.2012, 15:07     std::string в char* #7
Да вот как раз таки нужно освобождать. c_str() генерирует строку, и возвращает указатель на нее. Если к примеру изменить сам объект std::string после генерирования этой строки, то последняя в свою очередь не изменится. Нужно удалять эту строку как любой другой массив
C++
1
delete [] ptr;
Добавлено через 1 минуту
Хотя нет, я поспешил, и скорей всего не прав.
Bers
Заблокирован
11.06.2012, 15:09     std::string в char* #8
Цитата Сообщение от Toshkarik Посмотреть сообщение
Да вот как раз таки нужно освобождать. c_str() генерирует строку, и возвращает указатель на нее.
Хм... кстати.. а это вопрос:


Generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters.

A terminating null character is automatically appended.

The returned array points to an internal location with the required storage space for this sequence of characters plus its terminating null-character, but the values in this array should not be modified in the program and are only guaranteed to remain unchanged until the next call to a non-constant member function of the string object.

Нужно проверить, будет ли утечка.
Но вот сам лично я никогда не освобождал память, которую сам не создавал. И вроде бы утечек не было.


C++
1
2
3
4
5
6
7
8
9
10
int main()
{
    
    std::string test("trololo");
    const char* ptr = test.c_str();
 
   // delete [] ptr;  //если расскоментировать, получаем порчу памяти
 
    return 0;
}
итого: удалять стринговые данные нельзя
grizlik78
Эксперт C++
 Аватар для grizlik78
1882 / 1414 / 101
Регистрация: 29.05.2011
Сообщений: 2,958
11.06.2012, 15:13     std::string в char* #9
Строку, которую возвращает std::string::c_str() освобождать не только не надо, но и нельзя.
Ну и &test[0] для std::string не годится не только из-за возможной не непрерывности, но и потому, что строка не обязательно будет заканчиваться нулём. Скажем std::string::data() возвращает непрерываный блок, но нуля в конце там тоже не обещается, в отличие от c_str().
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
11.06.2012, 15:14  [ТС]     std::string в char* #10
Цитата Сообщение от Bers Посмотреть сообщение
Ни в коем случае. Данные являются собственностью стринга, а не вызывающей стороны.
Ну я когда свой кривостринг делал, sting::operator char* возвращал копию. Соответственно нужен был delete.
grizlik78
Эксперт C++
 Аватар для grizlik78
1882 / 1414 / 101
Регистрация: 29.05.2011
Сообщений: 2,958
11.06.2012, 15:15     std::string в char* #11
Цитата Сообщение от taras atavin Посмотреть сообщение
Ну я когда свой кривостринг делал, sting::operator char* возвращал копию.
Стандартный тоже может возвращать копию. Только копией этой владеет сам объект строки.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.06.2012, 15:17     std::string в char* #12
Да, сгенерированная строка не меняется при изменении самого объекта. Нужно вызывать повторно функцию, чтоб изменилась и Си строка. Мысль про освобождение памяти - скорей всего выделенная память под строку освобождается при удалении объекта.
grizlik78
Эксперт C++
 Аватар для grizlik78
1882 / 1414 / 101
Регистрация: 29.05.2011
Сообщений: 2,958
11.06.2012, 15:20     std::string в char* #13
Цитата Сообщение от Toshkarik Посмотреть сообщение
Да, сгенерированная строка не меняется при изменении самого объекта.
Этого, кстати, тоже никто не обещает. Результат c_str() можно считать валидным лишь до тех пор, пока для строки вызываются только константные функции.
Bers
Заблокирован
11.06.2012, 15:22     std::string в char* #14
Цитата Сообщение от taras atavin Посмотреть сообщение
Ну я когда свой кривостринг делал, sting::operator char* возвращал копию. Соответственно нужен был delete.
Есть правило: кто память выделял, тот её и освобождает.
К тому же, тот кто выделял - тот знает точно: как он выделял. А значит лучше знает, как правильно освободить. Чего не скажешь о вызывающей стороне.

Единственное исключение из этого правила - это специализированные инструменты, которые управляют временем жизни объекта (всякие там смартпоинтеры).

Если придерживаться этого правила, то путаницы не возникает.
На примере std::string видно, что она этого правила придерживается.
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
11.06.2012, 15:24  [ТС]     std::string в char* #15
Это константа.
diagon
Higher
 Аватар для diagon
1920 / 1186 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
11.06.2012, 17:48     std::string в char* #16
Цитата Сообщение от Toshkarik Посмотреть сообщение
Да, сгенерированная строка не меняется при изменении самого объекта. Нужно вызывать повторно функцию, чтоб изменилась и Си строка. Мысль про освобождение памяти - скорей всего выделенная память под строку освобождается при удалении объекта.
Разве?
А мне казалось, что возвращается указатель на строку в объекте. Например. Но здесь надо стандарт читать.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.06.2012, 18:22     std::string в char* #17
Ну я вот так проверял. В любом случае и мой и Ваш варианты работают благодаря случаю. Как уже и сказали, строка действительна только до момента изменения самого объекта string.
Bers
Заблокирован
11.06.2012, 18:26     std::string в char* #18
Цитата Сообщение от diagon Посмотреть сообщение
А мне казалось, что возвращается указатель на строку в объекте.
Я это так понимаю:
Если внутри стринга данные лежат в непрерывном блоке, то было бы странным создавать новый блок, копировать туда данные, и выдавать наружу его указатель.
Ведь с таким же успехом можно сразу выдать указатель на итак уже имеющийся блок.

Однако, поскольку стандарт не запрещает реализовывать внутренее хранилище по разному. То - не факт, что это будет именно так.

Другими словами, в отдельных случаях (реализациях стринга) это может работать. А в каких то может и не сработать. В этом и заключается смысл слова:
Цитата Сообщение от grizlik78 Посмотреть сообщение
Этого, кстати, тоже никто не обещает.
Может быть будет работать. Может быть не будет. Если нужно гарантированно портабельное решение, то лучше на такое не опираться.

Добавлено через 3 минуты
Цитата Сообщение от Toshkarik Посмотреть сообщение
Ну я вот так проверял. В любом случае и мой и Ваш варианты работают благодаря случаю. Как уже и сказали, строка действительна только до момента изменения самого объекта string.
Есть предположение, что:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <string>
 
int main()
{
   std::string str = "12345";
   
   const char *cstr1 = str.c_str(),
              *cstr2 = 0;
   
   std::cout << str << '\n' << cstr1 << std::endl;
   
   str = "qwerty";
   
   cstr2 = str.c_str();
   
   std::cout << '\n' << str << '\n' << cstr1  //cstr1  выводит в режиме только для чтения мертвую память.
                << '\n' << cstr2 << std::endl;
   
   return 0;
}
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
11.06.2012, 18:26  [ТС]     std::string в char* #19
Не пойму, зачем вы обсуждаете подобные связи? Вопрос копия/оригинал имеет смысл только в контексте делита.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.06.2012, 18:29     std::string в char*
Еще ссылки по теме:

C++ ошибка в программе (cannot convert 'std::string {aka std::basic_string<char>}' to 'const char*')
char* vs std::string C++
IntelliSense: отсутствует оператор "<<", соответствующий этим операндам типы операндов: std::basic_ostream<char, std::char_traits<char> C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Bers
Заблокирован
11.06.2012, 18:29     std::string в char* #20
Pardon
Yandex
Объявления
11.06.2012, 18:29     std::string в char*
Ответ Создать тему
Опции темы

Текущее время: 21:17. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru