STL Iterators?
Идея "итератора", предложенная мной, интересна, но реальная точка зрения итераторов - навигация по контейнеру. Не как простой аксессуар.
Если ваш метод доступа один из многих, то итераторы - это путь, потому что вы сможете использовать их для перемещения в контейнере. Но если ваш метод доступа является простым средством получения, способным вернуть либо значение , либо факт, что нет значения , то ваш итератор, возможно, всего лишь прославленный указатель ...
Что приводит нас к ...
Умные указатели?
Смысл интеллектуальных указателей заключается в упрощении владения указателями. С помощью общего указателя вы получите ресурс (память), который будет использоваться совместно, за счет накладных расходов (совместно используемым указателям необходимо выделить целое число в качестве счетчика ссылок ...).
Вы должны выбрать: либо ваше значение уже находится внутри общего указателя, а затем вы можете вернуть этот общий указатель (или слабый указатель). Или ваше значение находится внутри необработанного указателя. Затем вы можете вернуть указатель строки. Вы не хотите возвращать общий указатель, если ваш ресурс еще не находится внутри общего указателя: Мир забавных вещей случится, когда ваш общий указатель выйдет из области видимости, удалив ваше Значение, не сказав вам ...
: - р
Указатели
Если ваш интерфейс имеет четкие сведения о владении своими ресурсами, и в силу того, что возвращаемое значение может быть NULL, тогда вы можете вернуть простой необработанный указатель. Если пользователь вашего кода достаточно глуп, игнорирует контракт интерфейса вашего объекта, или играет арифметику или что-то еще с указателем, то он / она будет достаточно глуп, чтобы сломать любой другой способ, которым вы выберете возвращать значение, поэтому не заморачивайся с умственно отсталыми ...
неопределенное значение
Если ваш тип Value на самом деле уже имеет какое-то "неопределенное" значение, и пользователь знает это и примет это для обработки, это возможное решение, подобное решению с указателем или итератором.
Но не добавляйте «неопределенное» значение в ваш класс Value , потому что проблемы, которую вы задали: вы в конечном итоге поднимите войну «ссылки против указателя» на другой уровень безумия. Пользователи кода хотят, чтобы объекты, которые вы им предоставляете, были либо в порядке, либо не существовали. Необходимость проверять все остальные строки кода, этот объект по-прежнему действителен, является болью и бесполезно усложнит код пользователя по вашей вине.
Исключения
Исключения обычно не так дороги, как хотелось бы некоторым людям. Но для простого аксессуара стоимость может быть не тривиальной, если ваш аксессуар используется часто.
Например, STL std :: vector имеет два метода доступа к своему значению через индекс:
T & std::vector::operator[]( /* index */ )
и
T & std::vector::at( /* index */ )
Разница в том, что []
составляет не-бросок . Таким образом, если вы получаете доступ за пределы вектора, вы сами по себе, вероятно, рискуете испортить память и рано или поздно произойдет сбой. Таким образом, вы действительно должны быть уверены, что вы проверили код, используя его.
С другой стороны, at
- это , выбрасывая . Это означает, что если вы получите доступ за пределы вектора, вы получите чистое исключение. Этот метод лучше использовать, если вы хотите делегировать другому коду обработку ошибки.
Я использую персонально []
, когда я получаю доступ к значениям внутри цикла, или что-то подобное. Я использую at
, когда я чувствую, что исключением является хороший способ вернуть текущий код (или вызывающий код), если что-то пошло не так.
И что?
В вашем случае вы должны выбрать:
Если вам действительно нужен молниеносный доступ, то проблема может быть в метании доступа. Но это означает, что вы уже использовали профилировщик в своем коде, чтобы определить, что это узкое место, не так ли?
; -)
Если вы знаете, что отсутствие значения может часто случаться, и / или вы хотите, чтобы ваш клиент передавал возможный нулевой / недействительный / любой семантический указатель на доступ к значению, тогда верните указатель (если ваше значение находится внутри указатель) или слабый / общий указатель (если ваше значение принадлежит общему указателю).
Но если вы считаете, что клиент не будет распространять это «нулевое» значение или что они не должны распространять нулевой указатель (или умный указатель) в своем коде, то используйте ссылку, защищенную исключением. Добавьте метод hasValue, возвращающий логическое значение, и добавьте бросок, если пользователь попытается получить значение, даже если его нет.
И последнее, но не менее важное: рассмотрите код, который будет использоваться пользователем вашего объекта:
// If you want your user to have this kind of code, then choose either
// pointer or smart pointer solution
void doSomething(MyClass & p_oMyClass)
{
MyValue * pValue = p_oMyClass.getValue() ;
if(pValue != NULL)
{
// Etc.
}
}
MyValue * doSomethingElseAndReturnValue(MyClass & p_oMyClass)
{
MyValue * pValue = p_oMyClass.getValue() ;
if(pValue != NULL)
{
// Etc.
}
return pValue ;
}
// ==========================================================
// If you want your user to have this kind of code, then choose the
// throwing reference solution
void doSomething(MyClass & p_oMyClass)
{
if(p_oMyClass.hasValue())
{
MyValue & oValue = p_oMyClass.getValue() ;
}
}
Итак, если ваша основная проблема заключается в выборе между двумя кодами пользователей, указанными выше, ваша проблема не в производительности, а в «эргономичности кода». Таким образом, решение об исключении не следует откладывать из-за потенциальных проблем с производительностью.
: -)