Форум программистов, компьютерный форум 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 к указателю на нуль-терминальную строку? Как?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
11.06.2012, 14:13     std::string в char*
Посмотрите здесь:

Ошибка при компиляции "Cannot convert `std::string' to `const char*" C++
C++ Перевод массива char в std::string в определенном формате
std::string и/или char* C++
C++ запрошено преобразование от ‘const std::string*’ к нескалярному типу ‘std::string’
(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const& C++
C++ Где и почему используют ту или иную строку std::string, char[], System::String^ ?
C++ ошибка в программе (cannot convert 'std::string {aka std::basic_string<char>}' to 'const char*')
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
11.06.2012, 18:30     std::string в char* #21
Цитата Сообщение от Bers Посмотреть сообщение
Есть предположение, что:
Я тоже так думаю. Хотя возможно где то хранятся эти самые строковые литералы. Нужно попробовать проверить со строкой, вводимой пользователем.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
grizlik78
Эксперт С++
 Аватар для grizlik78
1888 / 1420 / 103
Регистрация: 29.05.2011
Сообщений: 2,970
11.06.2012, 18:34     std::string в char* #22
Bers, что вкладывается в понятие мёртвая память и почему она мёртвая в том примере?
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1285 / 1219 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
11.06.2012, 18:34     std::string в char* #23
Цитата Сообщение от Bers Посмотреть сообщение
то было бы странным создавать новый блок...
Если и правда терзают сомнения, то достаточно сделать ДВА вызова c_str и сравнить эти указатели. Если они разные, то возвращается копия (но это не так, разумеется). А если одинаковые, то на внутренний буфер.
И я не знаю, как работает codepad, но в MSVC в данной программе вообще std::sting str может быть удалён оптимизирующим компилятором, как ненужный объект. Этим можно было бы объяснить неожиданное поведение программы.
Bers
Заблокирован
11.06.2012, 19:16     std::string в char* #24
Цитата Сообщение от grizlik78 Посмотреть сообщение
Bers, что вкладывается в понятие мёртвая память и почему она мёртвая в том примере?
C++
1
2
3
4
5
char* str = new char[100500];
str[0] = '1';
str[1]= '\0'
delete [] str;
std::cout<<str<<std::endl;
Память сдохла. Но какое то время теоретически может хранить якобы актуальное значение

Добавлено через 2 минуты
Цитата Сообщение от Deviaphan Посмотреть сообщение
но это не так, разумеется
Ни разу не сталкивался с ситуациями, где это было бы так. Однако, в книжке по STL Джосаттис об этом предупреждает. Он говорит - стандарт не гарантирует, и полагаться на это нельзя.
grizlik78
Эксперт С++
 Аватар для grizlik78
1888 / 1420 / 103
Регистрация: 29.05.2011
Сообщений: 2,970
11.06.2012, 19:18     std::string в char* #25
Ясно. Но непонятно из-за чего такие подозрения в том коде. Вывод строки работает с константной ссылкой на строку и не может вызывать неконстантные функции. А раз так, то указатель остаётся валидным.
Bers
Заблокирован
11.06.2012, 19:24     std::string в char* #26
C++
1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
       std::string str = "12345";
       const char *cstr1 = str.c_str(),   //смотрит на 12345
       cstr2 = 0;
       std::cout << str << '\n' << cstr1 << std::endl;
       str = "qwerty";        //внутреннее хранилище изменилось
       cstr2 = str.c_str();
       std::cout << '\n' << str << '\n' << cstr1 //по прежнему смотрит на 12345
                 << '\n' << cstr2 << std::endl;
       return 0;
}
Строка изменилась. И как бы ей и не нужны старые данные, но старый указатель об этом не знает.
grizlik78
Эксперт С++
 Аватар для grizlik78
1888 / 1420 / 103
Регистрация: 29.05.2011
Сообщений: 2,970
11.06.2012, 19:30     std::string в char* #27
Ах, да, присваивание я пропустил. Что ж, там что угодно может быть, согласен.
Bers
Заблокирован
11.06.2012, 19:54     std::string в char* #28
Цитата Сообщение от grizlik78 Посмотреть сообщение
Ах, да, присваивание я пропустил. Что ж, там что угодно может быть, согласен.
Просто в студии, когда внутренее хранилище меняется, то и старые указатели смотрят на это новое внутренее хранилище (иногда). А иногда уже не смотрят (когда реалок памяти стринга).

Как бы.. выдавая наружу си-строку, стринг нарушает инвариант своего класса. Это опасная процедура. И нужна лишь для совместимости с старым си-кодом. Лучше это избегать.

Я пользую сие только для сишных конструкций, и никогда при этом стринг не изменяю. Итак проблем хватает.
Deviaphan
Делаю внезапно и красиво
Эксперт C++
 Аватар для Deviaphan
1285 / 1219 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
11.06.2012, 19:57     std::string в char* #29
Цитата Сообщение от Bers Посмотреть сообщение
Ни разу не сталкивался с ситуациями, где это было бы так.
В вышеприведённом коде в кодепаде всё выглядит так, будто возвращалась копия.
ТУт ещё такая фишка есть, что строки до 16 символов хранятся в объекте std::string в массиве фиксированного размера (в стеке) и только для бОльших строк выделяется память из кучи. С этим могло быть предыдущее поведение связанно.
Блудадей
 Аватар для Блудадей
59 / 6 / 1
Регистрация: 09.09.2011
Сообщений: 12
16.06.2012, 13:26     std::string в char* #30
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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 = "qwert";//уменьшен до 5 символов
   
   cstr2 = str.c_str();
   
   std::cout << '\n' << str << '\n' << cstr1 << '\n' << cstr2 << std::endl;
   
   return 0;
}
данный код выводит(не происходит повторного выделения):
12345
12345

qwert
qwert
qwert
так что, скорее всего c_str возвращает ссылку на оригинал.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
16.06.2012, 13:41     std::string в char* #31
Она не может возвращать ссылку на оригинал, сама строка может хранится в контейнере std::string блоками в разных участках памяти, что и писали выше. std::string::c_str() лишь генерирует Си строку, указателем на которую можно безопасно пользоваться до любого изменения строки. Вот тот при мер кода, который я так же приводил в пример на 2 странице:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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 << '\n' << cstr2 << std::endl;
   
   return 0;
}
Вот вывод.
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
16.06.2012, 15:00  [ТС]     std::string в char* #32
Цитата Сообщение от Toshkarik Посмотреть сообщение
Она не может возвращать ссылку на оригинал, сама строка может хранится в контейнере std::string блоками в разных участках памяти, что и писали выше.
И что?
Цитата Сообщение от Toshkarik Посмотреть сообщение
std::string::c_str() лишь генерирует Си строку, указателем на которую можно безопасно пользоваться до любого изменения строки.
си строка есть строка символов, хранимых подряд в одном месте и с терминальным нолём. Возвращается не список, не дерево, не массив и не иной контейнер си строк а сама строка. Значит после std::string::c_str() такая строка существует. Почему бы теперь ни назначить внутренний указатель на строку уже на неё? Раз уж память выделена. То есть сначала меняем размещение оригинал и ставим терминальный ноль, а потом уже возвращаем указатель. При этом длина строки продолжает храниться в готовом виде. С другой стороны, можно вернуть копию и при этом указатель на неё запомнить внутри, а при повторном std::string::c_str() верунть второй раз ту же копию. Я свой кривостринг сделала сначала с возвратом оригинала, причём, данные всегда хранились в виде комбинации динамической си строки (с терминальным нолём), её длины в отдельном поле.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class TSting
{
 protected:
  char *data; // нуль-терминальная строка
  unsigned long int count; // длина строки
 public:
  TString ();
  TString (TString &s);
  TString (char *s);
 ~TString ();
 TString operator +=(TString &s);
 TString operator +=(char *s);
 TString operator +=(char c);
 TString operator +(TString &s);
 TString operator +(char *s);
 TString operator +(char c);
 TString operator =(TString &s);
 TString operator =(char *s);
 TString operator =(char c);
 char &operator [] (unsigned long int number); // номирация с ноля
 unsigned long int Length();
 operator  unsigned long int (); //Тоже возвращает длину строки
};
при запросе длины строки, она возвращается из поля count. При любой операции строки, которая может изменить её длину, count обновляется. Если к строке TString добавляется си строка, то сначала в цикле считается её длина, потом выделяется память, потом count увеличивается на длину слагаемого оператором += и только потом происходит копирование из обеих строк, сначала из старого TString. Если строка TString созданётся на основе си строки, или ей присваивается си строка, то сначала счёт символов в цикле, потом выделение памяти, потом копирование, потом присваивание длины. В остальных случаях сразу выделение памяти, потом копирование, потом += для увеличения count. Потом переписал на возврат копии, за удаление которой отвечала вызывающая функция. Каждый раз возвращалась новая копия, но данные всё равно хранились подряд и с теримнальным нолём на конце. И покажи ка цитату из стандарта, гарантирующую, что символы стринга хранятся в разрозненных кусках. Если нет гарантии обратного, то это ещё ничего не значит.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
16.06.2012, 15:07     std::string в char* #33
Вы покажите цитату где я утверждал, что он всегда будет хранится в разных местах памяти? Ваш пост если честно ни о чем. Ваша реализация кого то там класса, это Ваша реализация, и я почти уверен, что она отличается от всех тех, что используют существующие компиляторы. Я могу привести другую цитату:
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.
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
16.06.2012, 15:24  [ТС]     std::string в char* #34
Цитата Сообщение от Toshkarik Посмотреть сообщение
Вы покажите цитату где я утверждал, что он всегда будет хранится в разных местах памяти?
Читай:
Цитата Сообщение от Toshkarik Посмотреть сообщение
на не может возвращать ссылку на оригинал, сама строка может хранится в контейнере std::string блоками в разных участках памяти,
Если не может вернуть из-за размещения, значит оно всегда такое. Иначе можно привести к подходящему размещению и потом вернуть указатель на внутренние данные.

Добавлено через 2 минуты
Цитата Сообщение от Toshkarik Посмотреть сообщение
и я почти уверен, что она отличается от всех тех, что используют существующие компиляторы.
Я сам в этом уверен. Но тем не менее, отдельные аспекты класса могли придти в голову не только мне. На свой класс я ссылаюсь только как пример принципиальной возможности возвращать указатель хоть на оригинал, хоть на копию. И при возврате указателя на оригинал разработчики класса могут специально позаботиться обо всех особенностях размещения, чтоб они этот фокус позволяли. Мораль проста: если указатель на оригинал смог вернуть даже я всего через 3 месяца от начала изучения языка, то уж тем более это мог сделать, например, Страуструп, если бы счёл это целесообразным.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
16.06.2012, 15:26     std::string в char* #35
Цитата Сообщение от taras atavin Посмотреть сообщение
сама строка может хранится в контейнере std::string блоками в разных участках памяти,
Что не понятного из этой фразы? Или Вы считаете, что должна быть проверка, находится ли строка в одном месте или кусками, и на основании этого возвращать указатель? И опять же:
Цитата Сообщение от Toshkarik Посмотреть сообщение
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.
Функция генерирует си-строку...
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
16.06.2012, 15:44  [ТС]     std::string в char* #36
Цитата Сообщение от Toshkarik Посмотреть сообщение
Что не понятного из этой фразы?
"Может хранить" не значит, что именно так она и хранит, фраза лишь утверждает, что нет гарантии обратного. Но обратное всё же возможно. И если оно для его то нудно разработчикам класса, то именно так и будет сделано. Можно даже сделать так, что по дефолту строка разрорвана на фрагменты, а sts::string::c_str() сначала собирает их в один во внутреннем представлении (ему же всё равно сначала надо собрать их в один), а только потом возвращает указатель и после него до следующего изменения строка уже хранится единым блоком до следующего своего изменения. Как вариант - можно хранить список нультерминальных массивов символов с индивидуальными полями длины и ещё общим полем длины, а по sts::string::c_str() приводить его к одному нультерминальному массиву символов через двойной указатель с дублированным полем полной длины.

Добавлено через 3 минуты
Гипотез можно строить много, без строгих формулировок в стандарте (а "может" - не строгая, так как ничего не гарантирует) только листинг и спецификация реализации могут пролить свет на то, как в действительности хранятся данные и что возвращается.

Добавлено через 2 минуты
Цитата Сообщение от Toshkarik Посмотреть сообщение
Функция генерирует си-строку...
Эйси. Но "генерирует копию данных в виде си строки" и "генерирует си строку и заменяет ею текущее внутреннее представление" - далеко не одно и тоже, но то и то будет "генерирует си строку".
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
16.06.2012, 15:52     std::string в char* #37
Да о чем Вы вообще? Куда Вас понесло?
Цитата Сообщение от taras atavin Посмотреть сообщение
не значит, что именно так она и хранится,
Я и написал, что МОЖЕТ хранить, и не писал обратного, не нужно пожалуйста осознанно коверкать смысл фразы.
Цитата Сообщение от taras atavin Посмотреть сообщение
И если оно для его то нудно разработчикам класса
Вы сами эту фразу поняли?

Все выше Вами описанное c_str() не обязана делать, в ее задачу лишь входит генерация Си-строки, и возвращение указателя на нее, ни слова о том, что она должна как то объединять внутреннее представление строки, или вообще делать что то еще с объектом. Так зачем же разработчикам усложнять себе жизнь?
Цитата Сообщение от taras atavin Посмотреть сообщение
Но "генерирует копию данных в виде си строки" и "генерирует си строку и заменяет ею текущее внутреннее представление" - далеко не одно и тоже, но то и то будет "генерирует си строку".
Вы хоть читали полностью эту цитату? Покажу 3 раз:
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.

Добавлено через 3 минуты
PS: синоним слова генерировать - создавать. Функция создает массив символов, ограниченный ноль-символом, и по содержанию идентичный строке-объекту.
taras atavin
Ушёл с форума.
 Аватар для taras atavin
3569 / 1752 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
16.06.2012, 15:59  [ТС]     std::string в char* #38
Цитата Сообщение от Toshkarik Посмотреть сообщение
Все выше Вами описанное c_str() не обязана делать, в ее задачу лишь входит генерация Си-строки, и возвращение указателя на нее, ни слова о том, что она должна как то объединять внутреннее представление строки, или вообще делать что то еще с объектом. Так зачем же разработчикам усложнять себе жизнь?
Ну она же всё равно должна объединить данные объекта.

Добавлено через 1 минуту
Цитата Сообщение от Toshkarik Посмотреть сообщение
PS: синоним слова генерировать - создавать.
Думаешь, я этого не понимаю?

Добавлено через 51 секунду
Модераторы, прикройте эту тему с хвостом ни о чём, а то она давно в офтоп свалилась.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 51
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
16.06.2012, 16:00     std::string в char* #39
Она не должна ничего объединять. Она должна создать массив символов ( Си-строку ), идентичный по содержанию string-объекту.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.06.2012, 17:05     std::string в char*
Еще ссылки по теме:

char* vs std::string C++
Как можно считывать из строки (std::string или char*) данные при помощи cin C++
IntelliSense: отсутствует оператор "<<", соответствующий этим операндам типы операндов: std::basic_ostream<char, std::char_traits<char> C++
Error: ambiguous overload for 'operator<<' (operand types are 'std::ofstream {aka std::basic_ofstream<char>}' C++
C++ Std::string в const char*

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

Или воспользуйтесь поиском по форуму:
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7955 / 4717 / 318
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
16.06.2012, 17:05     std::string в char* #40
5 The char-like objects in a basic_string object shall be stored contiguously. That is, for any basic_string
object s, the identity &*(s.begin() + n) == &*s.begin() + n shall hold for all values of n such that 0
<= n < s.size().
Итого - по кускам строка хранится НЕ может. Она обязана хранится в непрерывной области памяти.

6 References, pointers, and iterators referring to the elements of a basic_string sequence may be invalidated
by the following uses of that basic_string object:
— as an argument to any standard library function taking a reference to non-const basic_string as an
argument.234
— Calling non-const member functions, except operator[], at, front, back, begin, rbegin, end, and
rend.
Итого при вызове не константных функций, за исключением некоторых - итераторы, указатели могут стать не валидными.

const charT* c_str() const noexcept;
const charT* data() const noexcept;
1 Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].
2 Complexity: constant time.
3 Requires: The program shall not alter any of the values stored in the character array.
Итого - не генерируется никакой новой строки.

Что, в стандарт сложно заглянуть?

Добавлено через 26 минут
Хотя все понятно. В стандарте С++98 ничего такого не описано.
Yandex
Объявления
16.06.2012, 17:05     std::string в char*
Ответ Создать тему
Опции темы

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