eao197 on the Web Сайт Евгения Охотникова |
[ Главная | Проекты | Описания | Об авторе | Лицензия ] |
C++ tricks: ensure_arg_validiy
Наверняка все уже украденоизобретено до нас, но я раньше
такого не видел. Поэтому порадовался, когда до этого додумался. Итак,
конструктор какого-то C++ класса получает набор аргументов. На аргументы
накладываются некоторые требования. Нужно порождать исключение в конструкторе,
если пользователь не выполняет эти требования. Как это обычно делается?
Наверное, как-то вот так:
class some_class_t {
private :
// Имя должно состоять из определенного набора символов и
// длина имени должна быть не меньше N и не больше M.
const std::string m_name;
// Час, должен быть в диапазоне [0..23].
const unsigned int m_hour;
// Минута, должна быть в диапазоне [0..59].
const unsigned int m_minute;
...
public :
// Вот и конструктор.
some_class_t(
const std::string & name,
unsigned int hour,
unsigned int minute )
// Вот это важно! Сначала атрибуты получают значения...
: m_name( name )
, m_hour( hour )
, m_minute( minute )
{
// ...а уже потом выполняется проверка.
ensure_name_validity( m_name );
ensure_hour_validity( m_hour );
ensure_minute_validity( m_minute );
...
}
...
};
Что здесь нехорошо? А то, что если инициализация аргументов дорогая, то мы сначала платим цену инициализации, а только затем начинаем делать проверки. Но ведь ее можно и не платить ;) Вот так:
// Вот такие валидаторы нам нужны:
const std::string &
ensure_name_validity( const std::string & arg ) { ...; return arg; }
unsigned int
ensure_hour_validity( unsigned int arg ) { ...; return arg; }
unsigned int
ensure_minute_validity( unsigned int arg ) { ...; return arg; }
class some_class_t {
...
public :
// Вот и конструктор.
some_class_t(
const std::string & name,
unsigned int hour,
unsigned int minute )
// Вот это важно! Параметры проверяются до
// инициализации атрибутов.
: m_name( ensure_name_validity( name ) )
, m_hour( ensure_hour_validity( hour ) )
, m_minute( ensure_minute_validity( minute ) )
{
...
}
...
};
По большому счету, это экономия на спичках. Но все равно так выглядит логичнее, что ли.
А еще эту идею можно развить до явной декларации требований к атрибутам. Вот, допустим, так можно явно прописать в коде, какие требования налагаются на параметр name конструктора нашего демонстрационного класса:
// Валидатор параметра name.
struct valid_name_t {
const std::string & m_name;
valid_name_t( const std::string & name )
: m_name( ensure_name_validity( name ) )
{}
};
// Теперь требование к аргументу name может быть указано
// прямо в описании конструктора.
class some_class_t {
public :
some_class_t(
const valid_name_t & name,
... )
: m_name( name )
...
};
По большому счету, развивать этот подход можно и дальше. Таким образом можно прописывать требования не только к параметрам конструктора, но и аргументам обычных функций/методов. В общем, если где-то нужно применять defensive programming, то есть с чем поиграться.
© 2003-2005 Е.А. Охотников
$LastChangedDate: 2009-08-06 17:10:23 +0400 (Чт, 06 авг 2009) $