Лекции.Орг


Поиск:




Физическое и логическое постоянство объектов. Модификатор mutable




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

//тело класса

// Функция преобразования даты в строку

const char * ToString (char _sep) const

{

// Размещаем результирующую строку в статическом локальном массиве

static char tempBuf[ 11 ];

sprintf(tempBuf, "%d%c%d%c%d", m_Year, _sep, m_Month, _sep, m_Day);

return tempBuf;

}

//выведим на экран ОДНУ дату-объект

Date d(2013, 5, 3);

const char * str = d.ToString('/');

std::cout << str << std::endl;

Если же мы будем пытаться выводить два и более дат-объектов, то мы будем выводить на экран только последний созданный объект.

Решить указанную проблему можно размещением буфера для результирующей строки непосредственно в памяти объекта-даты. В таком случае каждый объект получил бы индивидуальный ни с кем не разделяемый буфер. Однако, такой подход ведет к противоречию условия неизменности объекта — с логической точки зрения преобразование даты в строку не должно изменять состояние объекта-даты, что подчеркнуто модификатором const, а физически состояние измениться заполнением буфера символов.

Для случаев, когда в классе часть переменных-членов не образует логической основы понятия, а носит лишь вспомогательный характер, некий низкоуровневый механизм реализации, предусмотрено ключевое слово mutable. Такой модификатор переменной-члена разрешает изменение состояния даже если это происходит внутри функции-члена с модификатором const.

//тело класса

// Буфер для строкового представления. Можно изменять даже в const-методах

mutable char m_tempBuf[ 10 ];

 

public:

 

//...

 

// Функция преобразования даты в строку

const char * ToString (char _sep) const

{

// Размещаем результирующую строку в мутирующем буфере внутри объекта

sprintf(m_tempBuf, "%d%c%d%c%d", m_Year, _sep, m_Month, _sep, m_Day);

return tempBuf;

}

Представляется возможным повысить производительность операции ToString для класса Date, если избежать переформирования строкового представления при отсутствии изменения состояния данных о годе, месяце, дне. Для этого понадобится еще одна “мутирующая” переменная-член, означающая, что объект не менял своего состояния, соответственно, буфер содержит нужные символы:

Буфер для строкового представления. Можно изменять даже в const-методах

mutable char m_tempBuf[ 10 ];

 

// Флаг валидности содержимого буфера

mutable bool m_BufferValid;

Флаг устанавливается в значение false при создании объекта

Флаг также устанавливается в значение false при изменении состояния объекта

// Функция преобразования даты в строку

const char * ToString (char _sep) const

{

// Переформируем буфер только если он в неактуальном состоянии

if (! m_BufferValid)

{

// Размещаем результирующую строку в мутирующем буфере внутри объекта

sprintf(m_tempBuf, "%d%c%d%c%d", m_Year, _sep, m_Month, _sep, m_Day);

 

// Буфер теперь актуален

m_Buffervalid = true;

}

 

return tempBuf;

}

Если таких “мутирующих” полей в классе появляется много, это скорее всего свидетельствует о необходимости выноса части состояния объекта в другой вспомогательный объект, отдельно отвечающий за физическую часть.

//тело класса

struct StringRepr

{

char m_tempBuf[ 10 ];

bool m_isValid;

}

StringRepr* m_pStringRepr;

В целом, для объекта-даты такое решение является чересчур громоздким, однако такой подход вполне пригоден для более крупных объектов, обновление физической части которых занимает существенное время.

 

20. Класс std::string из стандартной библиотеки. Основная функциональность, способы применения. Особенности внутренней структуры.

Многие программисты, предпочитающие другие языки программирования, часто нарекают на сложность работы со строками в С++. Следует отметить, что эта критика, в основном, направлена на базовое представление строк в языке С в виде массива символов с нулевым завершителем. Действительно, в языке С, реализация вышеупомянутых операций несколько затруднительна, поскольку требует постоянного рассуждения о памяти для хранения символов, использования низкоуровневых функций наподобие strcpy и strcmp, расстановки нулевых завершителей вручную в ряде ситуаций.

Принципы объектно-ориентированного программирования, предоставляемые С++, позволяют эффективно сочетать потребности программистов в удобстве работы со строками вместе с производительностью низкоуровневого представления. В частности, стандартная библиотека предлагает для нужд работы со строками мощный готовый класс std::string, доступный в заголовочном файле <string>.

Этот класс определяет необходимые конструкторы, средства для копирования и перемещения, деструктор. Типичная реализация оптимизирует хранение символов таким образом, что для строк небольшого размера (до 16 символов), кои встречаются в большинстве программ наиболее часто, вообще не происходит динамического выделения памяти. Вместо этого реализация хранит символы в статическом буфере до тех пор, пока строка не увеличивается в размере до достаточно длинной. При дальнейшем росте, std::string выделяет динамическую память подобно векторам из дисциплины “Структуры и алгоритмы обработки данных”.

 

В связи с этим, объекты std::string можно свободно присваивать, передавать в качестве аргументов функций, возвращать из функций как результат, создавать временные объекты для формирования строк из фрагментов.

Класс std::string также интенсивно использует механизмы перегрузки операторов, в частности:

● оператор индексной выборки [] для обращения к конкретным символам строки;

● операторы +, += для конкатенирования строк;

● операторы сравнения (==,!=, <, <=, >, >=);

● операторы <<, >> для ввода вывода через потоки (консоль, файлы).

 

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

 

Также, класс std::string предлагает широкий набор вспомогательных методов, полезных для типичных задач со строками. Среди наиболее часто используемых следующие методы:

● size, length - методы определения длины;

● empty - метод определения пустоты строки;

● reserve, capacity - средства резервирования места для хранения символов заранее;

● clear - метод очистки строки;

● insert/erase - вставка/удаление фрагментов;

● replace - замена фрагментов на другие;

● find, rfind, find_first_of, find_last_of - поиск фрагментов;

● substr - получение подстроки;

● с_str - преобразование к строке в стиле языка С (указатель на const char *).

 





Поделиться с друзьями:


Дата добавления: 2016-07-29; Мы поможем в написании ваших работ!; просмотров: 644 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Логика может привести Вас от пункта А к пункту Б, а воображение — куда угодно © Альберт Эйнштейн
==> читать все изречения...

792 - | 790 -


© 2015-2024 lektsii.org - Контакты - Последнее добавление

Ген: 0.01 с.