Consider the following example:
typedef struct Collection
{
...
} Collection;
typedef struct Iterator
{
Collection* collection;
} Iterator;
Iterator is to offer collection-modifying functions, hence it holds address of a non-const Collection. However, it is also to offer non-modifying functions, which are perfectly legal to use with a const Collection.
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
}
I'm looking for a solution in C. I do see some options:
1. At Init, cast Collection to non-const. It's probably not undefined behaviour because the object ultimately should not get modified. But it is hair-raising, as having a const object, doing this is asking for trouble. The Iterator is to become a widely used, generic mechanism for working with collections. Having no compiler warnings when one is about to modify a const collection is really bad.
2. Two iterator types, one being a read-only version with a const Collection* member. This complicates usage, potentially requires duplication of some functions, possibly reduced efficiency due to translation step. I really do not want to complicate API and have two different structs along with two sets of functions.
3. Iterator having both pointers, and Init taking both Collection pointers.
typedef struct Iterator
{
const Collection* collectionReadable; // use this when reading
Collection* collectionWritable; // use this when writing
} Iterator;
When having a const Collection, the non-const argument has to become NULL and ultimately trying to modify the collection would crash (trying to dereference NULL pointer), which is good (safe). We have extra storage cost. It is awkward, taking two pointers of the same collection.
I'm also a bit worried about compiler seeing both pointers in same context, meaning that if the Collection gets modified through the writable pointer, the compiler has to realize that the read-only pointer may be pointing to the same object and it needs to be reloaded despite having the const qualifier. Is this safe?
Which one would you pick and why? Do you know any better approach to this problem?