【问题标题】:How to use a const C struct when the super-struct refers to a non-const?当超结构引用非常量时如何使用 const C 结构?
【发布时间】:2015-03-21 12:59:42
【问题描述】:

考虑以下示例:

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. 在 Init 中,将 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 集合时,非 const 参数必须变为 NULL,最终尝试修改集合会崩溃(尝试取消引用 NULL 指针),这很好(安全)。我们有额外的存储费用。这很尴尬,取同一个集合的两个指针。

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

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

【问题讨论】:

  • 为什么 SomeFunction have 需要一个指向 const 的指针?只需让用户传递一个非 const 对象即可。
  • @reader 在无数情况下,函数“保证”它们不会修改对象。它有利于优化并且在多线程代码中是无价的。

标签: c struct constants qualifiers


【解决方案1】:

是的,有两个指向同一个对象的指针是安全的,一个是常量,另一个是非常量。 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 限定符并不完美。当您遇到此类问题时,有很多用例,最简单的方法通常是接受它并不完美并进行类型转换。

【讨论】:

  • 我不确定类型转换是最好的解决方案,因为 Iterator 将成为外部广泛使用的对象的具体细节。而且我认为要求所有用户打破他们的 const corectness 是不好的。否则我同意你的看法——如果只在内部使用,我可以控制使用,类型转换可能是最好的。你的回答实际上让我更倾向于第三种选择,但我仍然没有决定。
猜你喜欢
  • 1970-01-01
  • 2016-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多