В параметре функции, который является указателем (foo (void * bar)), вы можете использовать const, чтобы указать, что либо сам указатель (параметр) является постоянным (foo (void * const bar)), и / или данные, которые указатель указывает на константу (foo (void const * bar)).
Однако в случае foo (void const * bar) это просто гарантия для вызывающей стороны, что foo не будет пытаться изменить данные, на которые указывает bar. Это не дает bar никакой гарантии того, что область памяти, на которую указывает bar, всегда будет действительной.
В тех случаях, когда вы работаете с постоянными данными в исполняемом образе, если вы можете предоставить такую гарантию для foo и если foo необходимо сохранить ссылку на эти данные дольше, чем продолжительность вызова функции, foo может просто сохранить копию указатель, а не делать копию данных.
Есть ли способ закодировать эту гарантию в системе типов C ++?
Благодарю.
Вопрос: Есть ли способ указать в C ++, что указатель указывает на данные, которые всегда действительны?
A: Нет. У вас всегда есть возможность выстрелить себе в ногу 🙂
Не с необработанным указателем, но вы могли бы вместо этого использовать shared_ptr или unique_ptr, которые сообщали бы, что функция владеет указателем.
Нет реального способа гарантировать это, если вы примете указатель в качестве ввода. Однако вы можете сохранить таблицу допустимых указателей и позволить вашим входным данным быть индексом этой таблицы; Вы можете проверить это, убедившись, что индекс попадает в таблицу.
Если не считать этого, лучшее, что вы можете сделать, это перехватить исключение / сигнал, возникающий при использовании неверного указателя, и попытаться восстановить его.
подход, который я выбрал, заключается в создании представления класса, которое вводит семантику, которая определяет вспомогательные данные static
, затем просто убедитесь, что он не может быть сконструирован тривиально или данные переназначены.
так что нет, прямой языковой функции нет, но ввести эту семантику достаточно просто.
Вот иллюстрация того, как предотвратить случайное продвижение клиентами стандартных данных в бессмертный контейнер данных:
template <typename T>
class t_immortal_data_container {
public:
// how clients create t_immortal_data_container<T>,
// avoiding implicit promotions:
static t_immortal_data_container Create(T& pImmortalData) {
return t_immortal_data_container(pImmortalData);
}
~t_immortal_data_container() {
}
public:
...
private:
// private: ensure t_immortal_data_container<T> only can use
// this constructor:
t_immortal_data_container(T& pData) : d_immortalData(pData) {
}
private:
T d_immortalData; /* << as pointer or reference */
private:
// prohibited -- no definition
t_immortal_data_container() /* = delete */ ;
};
затем вы обновляете свою программу, чтобы принимать этот тип в качестве параметров, и соответственно обрабатывать случаи