2

考虑以下示例:

typedef struct Collection
{
    ...
} Collection;

typedef struct Iterator
{
    Collection* collection;
} Iterator;

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.在初始化时,将 Collection 转换为非常量。这可能不是未定义的行为,因为对象最终不应被修改。但它令人毛骨悚然,因为有一个 const 对象,这样做是自找麻烦。Iterator 将成为一种广泛使用的通用机制,用于处理集合。当一个人要修改一个 const 集合时没有编译器警告真的很糟糕。

2.两种迭代器类型,一种是带有 const Collection* 成员的只读版本。这使使用复杂化,可能需要复制某些功能,可能由于翻译步骤而降低效率。我真的不想使 API 复杂化,并且有两个不同的结构以及两组函数。

3.具有两个指针的迭代器,而 Init 采用两个集合指针。

typedef struct Iterator
{
    const Collection* collectionReadable; // use this when reading
    Collection* collectionWritable;       // use this when writing
} Iterator;

当有一个 const 集合时,非常量参数必须变为 NULL 并且最终尝试修改集合会崩溃(尝试取消引用 NULL 指针),这很好(安全)。我们有额外的存储费用。这很尴尬,取同一个集合的两个指针。

我也有点担心编译器在同一上下文中看到两个指针,这意味着如果通过可写指针修改了 Collection,编译器必须意识到只读指针可能指向同一个对象,它需要尽管有 const 限定符,但仍会重新加载。这安全吗?

你会选择哪一个,为什么?你知道解决这个问题的更好方法吗?

4

1 回答 1

0

是的,有两个指向同一个对象的指针是安全的,一个是常量,另一个是非常量。const 只是意味着不能通过这个特定的指针修改对象,但如果有这样的指针,它可以通过其他指针修改。但是,尽管它是安全的,但这并不一定意味着您应该选择具有两个指针的解决方案。

有关完全正确运行的代码示例,请参见:

int x = 5;
const int *p = &x;
printf("%d\n", *p);
x = 7;
printf("%d\n", *p);

现在 *p 改变了,即使 p 是一个 const 指针。

您的目标是避免代码重复,因此您只需将 const 指针转换为非 const 指针。只要您不修改对象,它就是安全的。C标准库中有很多类似的例子。例如, strchr() 将一个 const char 指针放入字符串,然后返回一个 char 指针,以防万一字符串不是 const 并且您想通过返回值修改它。我会选择C标准库中采用的解决方案,即类型转换。

您基本上已经注意到 C 中的 const 限定符并不完美。当你遇到这样的问题时,有很多用例,最简单的方法通常是接受它并不完美并进行类型转换。

于 2015-03-21T13:07:39.703 回答