Рассмотрим следующий пример:Как использовать конструкцию const C, когда суперструктура ссылается на неконстантную?
typedef struct Collection
{
...
} Collection;
typedef struct Iterator
{
Collection* collection;
} Iterator;
итератора является предложение по сбору модифицирующие функции, следовательно, она имеет адрес неконстантного коллекции. Тем не менее, он также предлагает немодифицирующие функции, которые вполне законны для использования с коллекцией const.
void InitIterator(Iterator* iter, Collection* coll)
{
iter->collection = coll;
}
void SomeFunction(const Collection* coll)
{
// we want to use just non-modifying functions here, as the Collection is const
Iterator iter;
InitIterator(&iter, coll); // warning, call removes const qualifier
}
Я ищу решение в C. Я вижу некоторые варианты:
1. В начале, литой коллекции для не-const. Это, вероятно, не неопределенное поведение, потому что в конечном итоге объект не должен изменяться. Но это прическа, так как имеет объект const, и это требует неприятностей. Итератор должен стать широко используемым универсальным механизмом для работы с коллекциями. Отсутствие предупреждений компилятора, когда нужно изменить коллекцию const, действительно плохо.
2. Два типа итератора, один из которых является версией только для чтения с элементом const Collection *. Это усложняет использование, потенциально требует дублирования некоторых функций, возможно, снижает эффективность за счет перевода. Я действительно не хочу усложнять API и иметь две разные структуры вместе с двумя наборами функций.
3. Итератор, имеющий оба указателя, и Init, принимающий оба указателя на сборку.
typedef struct Iterator
{
const Collection* collectionReadable; // use this when reading
Collection* collectionWritable; // use this when writing
} Iterator;
При наличии константной Коллекции, неконстантная аргумент должна стать NULL и в конечном счете пытается изменить коллекцию врежется (пытаясь указатель разыменования NULL), что хорошо (безопасно). У нас есть дополнительная стоимость хранения. Это неудобно, принимая два указателя одной коллекции.
Я также немного обеспокоен тем, что компилятор видит оба указателя в том же контексте, что означает, что если коллекция будет модифицирована с помощью записываемого указателя, компилятор должен понять, что указатель только для чтения может указывать на один и тот же объект и его необходимо перезагрузить, несмотря на наличие определителя константы. Это безопасно?
Какой из них вы бы выбрали и почему? Знаете ли вы какой-либо лучший подход к этой проблеме?
Почему SomeFunction * имеет *, чтобы взять указатель на const? Просто позвольте пользователю передать объект non const. – reader
@reader Существует множество случаев, когда функции «гарантируют», что они не будут изменять объект. Он обеспечивает оптимизацию и бесценен в многопоточном коде. – user2231