Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Небольшое непонимание std::string.  (Прочитано 10153 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« : 28-11-2017 14:29 » 

Доброго дня.

Встретился такой нюанс, который немного удивил. Суть:
Код: (C++)
   struct A {string b;} a;

   a.b = "1234";

   cout << sizeof(struct A) << endl;
   for (unsigned int i = 0; i < sizeof(struct A); i++) cout << *((char*)&a + i);
   cout << endl << a.b << endl << endl;

   a.b = "ABCDEFGHIJKLMNO"; // 15 символов.

   for (unsigned int i = 0; i < sizeof(struct A); i++) cout << *((char*)&a + i);
   cout << endl << a.b << endl << endl;

   a.b = "ABCDEFGHIJKLMNOP"; // 16 уже частично в куче.

   for (unsigned int i = 0; i < sizeof(struct A); i++) cout << *((char*)&a + i);
   cout << endl << a.b << endl;

Результат:
24
яn    1234 яяяЪjЎvНkЎv
1234

яn    ABCDEFGHIJKLMNO
ABCDEFGHIJKLMNO

`$             EFGHIJKLMNO
ABCDEFGHIJKLMNOP

Вопрос: как правильно организовать ввод и вывод нескольких string в бинарный файл? Как правильно разделить данные и несколько string объектов в структуре?
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #1 : 28-11-2017 16:57 » 

std::string это класс, и работать с ним как с нуль терминальной строкой, крайне странно. Хочеш получить нуль терминальную строку: в классе string есть метод c_str().
А со строкой можно рабоать обычно:
Код: (C++)
struct A {
   std::string a;
   std::string b;
   std::string c;
};

std::string str = "123456";
std::cout << str << std::endl;
std::cin >> str;
Абсолютно также и с файлами.
« Последнее редактирование: 28-11-2017 17:00 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 28-11-2017 17:11 » 

Странно не это: я думал, что в структуре будет храниться только указатель на объект, а сам объект целиком будет в куче. Оказалось, что структура сильно вырастает в размере, часть строки хранится в одном месте, часть в другом.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #3 : 28-11-2017 17:22 » 

Сам класс и его внутрение данные будут хранится в структуре. А вот сама строка будет хранится в куче. Поскольку  string создает строку динамически.
« Последнее редактирование: 28-11-2017 17:25 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 28-11-2017 17:37 » 

Получается, что если его создать динамически, то будет указатель на структуру, а в ней указатель на данные. Когда я реализую что-нибудь похожее, то пользуюсь другим подходом:
Код: (C)
typedef struct
{
   unsigned int size;
   char[] data;
} string;

string* create(char* source)
{
...
   string* tstring = (string*)malloc(sizeof(string) + strlen(source) + 1);
...
   return tstring;
}

void destroy(string* tstring);

string* clone(string* tstring);

...
Но я уже понял, что объявление класса без new задействует внутренний учёт компилятора. Тем не менее, сам факт неоднозначного места хранения данных мне не понравился.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #5 : 28-11-2017 17:43 » 

Как раз тут все однозначно. Ты еше питон не изучал? Там веселье с классами по полной программе.

PS. Перестань мыслить категориями С. Классы добавляют свою специфику.
« Последнее редактирование: 28-11-2017 17:47 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 28-11-2017 19:01 » 

Ты еше питон не изучал?
Не, таких задач у меня не было. Так что знакомство с питоном ограничилось зоопарком. Улыбаюсь
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 28-11-2017 22:57 » 

Внутреннее хранение — это оптимизация для коротких строк. Частое выделение малых блоков, во-первых, затратно по времени, во-вторых, фрагментирует память. Внутренний буфер использует через union туже память, что и параметры, обслуживающие строку. При использовании внутреннего буфера они просто не нужны, а при переходе к внешнему буферу поля переинициализируются.

Малые блоки хорошо оптимизируются алокаторами с пулами разноразмерных блоков.

И главное: ни в коем случае не надо лезть в кишки и вообще думать, что умнее компилятора. Чем проще написано, тем лучше будет оптимизировано.

При должном знании можно залезть в кишки, но не с целью использовать что-то мимо интерфейса, а чтобы сделать свой аналог. Пример: аналог std::string, поддерживающий copy on write.
« Последнее редактирование: 28-11-2017 23:35 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 29-11-2017 09:21 » 

Я собственно туда полез из интереса - как так размер, казалось бы, небольшой структуры вырос до гигантского. Вот, теперь разобрался.

Но пока не очень ясна работа именно с бинарными потоками. Есть метод std::ostream::write() использую его, но может быть есть более удобный вариант. И запись строк приходится вести через явное указание их размера, возможно есть метод реализующий сохранение без собственных сочинений? Ну, что поделаешь, пока многое изучаю.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #9 : 29-11-2017 17:06 » 

Aether, Я лично стараюсь с чужими классами обрашаться как с черным яшиком. Дернеш за веревочку, получиш один результат, за другую, другой. В любой момент могут поменять реализацию класса. И если ты использовал не дркументированные функции оннного, то получиш по ушам от компилятора. Свои собственные классы также стараюсь делать черным яшиком.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Aether
Специалист

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 29-11-2017 18:45 » new

Я сейчас про документированные методы. std::ostream::write() позволяет выводить данные в двоичном виде, а обычный способ через << выводит только в десятичном виде, либо у меня документация не совсем корректная?
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 29-11-2017 21:06 » 

Функция вида std::ostream& operator<< (std::ostream&, const TYPE&). Пишешь такое для своего типа и выводишь как хочешь.
Функции для некоторых типов, как пример:
http://www.cplusplus.com/reference/ostream/ostream/operator-free/

А это для готовые методы для встроенных типов:
http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/

IMHO, использование << выглядит ужасно. Можно было бы сделать template <class T> std::ostream& std::ostream::put(const T&) и специфицировать в своем коде. Использование было бы тоже цепочечным, но классического вида:
Код: (C++)
os
    .put("n = ")
    .put(123)
    .endl();
Для простейших выводов пользуюсь сишными printf и puts, более чем. А для бинарного хорошо подходит такое же классическое write.
« Последнее редактирование: 29-11-2017 21:08 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines