27 / 27 / 4
Регистрация: 02.11.2010
Сообщений: 370
1

string, c_str

06.07.2012, 17:52. Показов 51621. Ответов 35
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
функция string.c_str() возвращает const char*, что бы не изменяли строку напрямую. Но! Если явно преобразовать указатель к char*, то строка вполне изменяется.

C++
1
2
3
4
5
6
7
8
9
10
int main()
{
        string str = "qwerty";
        char *p = (char*)str.c_str();
        *(p+1) = 'k';
        
        cout << str;
        getch();
        return 0;
}

Угадайте что выведет.

Так вот, собственно вопрос: зачем столько шумихи вокруг инкапсуляции, если даже в стринге ее легко обойти?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
06.07.2012, 17:52
Ответы с готовыми решениями:

Буффер из std::string c_str()
Здравствуйте! такое дело: Проект на Qt5 и С++11. Есть форма с полем ввода. Введённое содержимое...

Безопасность передачи string.c_str() в качестве параметра
Есть некоторая функция которая принимает в себя си-строку, модифицирует ее (в т.ч. может увеличить...

Не работает преобразование с c_str()
Доброго времени суток. Пытаюсь определить расширение найденного файла путем сравнения со строкой:...

X=atof(s.c_str()); - ошибка в Builder10
Здравствуйте ! Помогите, пожалуйста, чайнику. Проблема такая: Создаю учебный проект простого...

35
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
06.07.2012, 19:59 21
Author24 — интернет-сервис помощи студентам
diagon, Специализация шаблонной функции объявленной в классе своим типом, все же не совсем внутри класса.
0
27 / 27 / 4
Регистрация: 02.11.2010
Сообщений: 370
06.07.2012, 20:06  [ТС] 22
Evg, ну то есть получается, что зря я храню характеристики персонажей в private?
Ведь проще напрямую взаимодействовать с переменными, чем через SetVal, GetVal
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
06.07.2012, 20:08 23
Ksan, Инкапсуляция. Я вам крайне советую почитать Герба Саттера. В коде, не относящемся к реализации класса (иерархии), используя его нормально (не используя хаки со специализациями и доступ к членам через смещение), вы можете использовать только public интерфейс класса, до private данных вам не дотянуться.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
06.07.2012, 22:45 24
Evg, ну то есть получается, что зря я храню характеристики персонажей в private?
Ведь проще напрямую взаимодействовать с переменными, чем через SetVal, GetVal
Да, если не предусмотрено "последействия" - т.е вы меняете переменну А, а она вызывает еще автоматом изменение переменной B ну и в тех случаях когда "односторонний" доступ к переменной (например только для записи)
0
0 / 1 / 1
Регистрация: 18.02.2012
Сообщений: 244
06.07.2012, 22:50 25
а если так?

C++
1
2
3
4
5
6
7
8
9
int main()
{
        char *str = "qwerty";
        char *p = str.c_str();
        *(p+1) = 'k';
        cout << str;
        getch();
        return 0;
}
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
07.07.2012, 00:29 26
Цитата Сообщение от Ksan Посмотреть сообщение
Evg, ну то есть получается, что зря я храню характеристики персонажей в private?
Ведь проще напрямую взаимодействовать с переменными, чем через SetVal, GetVal
В маленьком проекте - проще. В большом проекте (особенно если над ним работает несколько человек) такой подход резко увеличивает вероятность того, что накосячишь на ровном месте, а потом концов не соберёшь. А потому лучше сразу приучать себя к тому, чтобы делать правильно

В функциях GetVal, SetVal ты всегда можешь поставить печать и быстренько посмотреть трассу изменения и чтения величины. Обращаясь к полю напрямую такого ты сделать не сможешь. Т.е. такой подход в том числе более удобен с точки зрения отладки
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
07.07.2012, 00:32 27
Ну и еще такой фактор как рост, сейчас-просто, а завтра- все равно придется писать SetVal,GetVal ( например, если появится последействие )
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
07.07.2012, 00:35 28
Есть ещё и такое явление: чтобы понять, как делать правильно, нужно хорошо наступить на грабли тогда, когда делаешь неправильно. Тогда будешь намного более чётко понимать, а нафига делают так
2
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
07.07.2012, 00:40 29
Ну честно говоря это действительно не удобно и не особо читаемо.
Например в Builder-е попровлено это дело свойствами.Но опять таки это ведь надстройка IDE, а не язык...
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
07.07.2012, 00:49 30
Avazart, Все удобно и все читаемо, свойства это исключительно синтаксический сахар в большинстве случаев.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
07.07.2012, 00:52 31
Возможно дело вкуса
C++
1
2
A->B= 10;
int i=A->B;
На мой взгляд смотрится лучше нежели
C++
1
2
A->SetB(10);
int i=A->GetB();
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
07.07.2012, 01:22 32
На тему использования инкапсуляции. Представьте что вы написали код, в котором используется класс с открытыми полями, вот вы предоставили ваш код клиентам, клиенты вовсю используют вашу библиотеку, используют открытые поля и тут поступает просьба от клиентов или же вы сами решаете расширить функционал вашей программы и пишете код, который добавляет/удаляет поля в структуру или же переносит их в приватную область видимости структуры и пишите методы, которые работают с данными как-то по особенному, в зависимости от конкретного ТЗ, вот вы провели тесты, все хорошо, выкатываете обновление, клиенты обновляются... И вы получаете сотни гневных писем, т.к. после вашего обновления весь код который писали клиенты библиотеки придется переписывать! А теперь представьте, что вы сразу сделали доступ к элементам через интерфейс, а не напрямую, скольких бы проблем удалось избежать?
2
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
07.07.2012, 01:33 33
Лучший ответ Сообщение было отмечено как решение

Решение

вот поучительный код для любителей нарушать правила:
http://liveworkspace.org/code/... 5699a096fb
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>
int main()
{
  std::string str1 = "str";
  std::string str2 = str1;
 
  std::cout << "str1 = " << str1 << std::endl;
  std::cout << "str2 = " << str2 << std::endl;
 
  char* pStr1 = (char*) str1.c_str();
  pStr1[0] = 'x';
 
  std::cout << "str1 = " << str1 << std::endl;
  std::cout << "str2 = " << str2 << std::endl; // сюрприз
 
  return 0;
}
Output:
str1 = str
str2 = str
str1 = xtr
str2 = xtr // как же так. ведь эту строку не меняли.

Это происходит из-за того, что там std::string реализована с использованием оптимизации "копирование при записи". В восьмой студии строка без такой оптимизации сделана.
8
silent_1991
07.07.2012, 21:15
  #34

Не по теме:

DU, никогда не думал, что стандартный string copy-on-write реализует... В прошлом стандарте так же было?

0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
07.07.2012, 21:43 35
не силен в стандарте, но там это вроде не оговаривается. можно с такой оптимизацией, а можно и без нее. посмотрел в 2012 студии. там тоже такой оптимизации нет, а она уже с новым стандартом.
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,516
07.07.2012, 21:48 36
Цитата Сообщение от Ksan Посмотреть сообщение
так это же указатели. Они в любом случае указывают на один и тот же массив
Цитата Сообщение от Schizorb Посмотреть сообщение
Ksan, да... но в первом случае (когда строки разной длины) они у меня указывают на разные. Компилятор gcc.
я думаю что это происходит так
C++
1
string str = "12345"
выделяется память на 6 байт
C++
1
const char *p1 = str.c_str();
указатель на эту память
C++
1
str = "abcdef";
а здесь уже нужно 7 байт
в старый не влазит
выделяем новую память
C++
1
const char *p2 = str.c_str();
указатель уже на неё
старую удаляем НО.. значения в ней остались
посему
C++
1
cout << p1 << '\n' << p2 << endl;
выводит два РАЗНЫХ участка памяти (хотя по мнению менеджера памяти первая уже свободна)
и если выделить память еще раз и что то записать то вполне вероятно что
p1 выведет не 12345 а что то другое
а при
C++
1
2
3
string str = "qwerty";
.............
str = "abcdef";
буфер одинаковый и новая память не выделяется
а просто переписываются значения в том же буфере
2
07.07.2012, 21:48
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.07.2012, 21:48
Помогаю со студенческими работами здесь

Очень медленное выполнение .c_str() в minGW
Есть функция: sscanf(line.c_str(), &quot;%d\t%d\t%hu.%hu.%hu\t%hu:%hu:%hu\t%lf&quot;, &amp;tmpData.Pip,...

Visual c++ input().c_str() вводит мусор
Я создал стринг переменную, получил через getline cin значения, передал их в другой метод, спри...

реализация функции c_str() в моем классе Str
Ребята, вот есть у меня в классе Str данные: private: Vec&lt;char&gt; data; char* buffer; В...

c_str() или моя голова провалилась в пропасть
Здравствуйте товарищи, один и тот же код приводит меня к правильному решению в 9 билдере, а вот в...


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

Или воспользуйтесь поиском по форуму:
36
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru