Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


Физическое и логическое постоянство объектов. Модификатор 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; Мы поможем в написании ваших работ!; просмотров: 658 | Нарушение авторских прав


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

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

Человек, которым вам суждено стать – это только тот человек, которым вы сами решите стать. © Ральф Уолдо Эмерсон
==> читать все изречения...

4399 - | 4224 -


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

Ген: 0.007 с.