我在C中有一个简单的向量实现,它包含一个void *数组。由用户来决定实际类型。
我想'保证'向量不会改变其内容,所以我将数据存储为:
Struct _Vector{
UInt32 used;
UInt32 size;
const void** arr;
};
我不知道它是否被认为是“过度使用”我的常量正确性,但我尝试使用我的访问者/修饰符维护const正确性:
void vector_add(Vector *v, const void* const elem);
void vector_set(Vector *v, const UInt32 idx, const void* const elem);
当我从向量中返回一个元素时,它是一个指向用户数据的指针,所以我让用户通过丢弃内部数组中的常量来修改指向的数据。
void* vector_get(const Vector *v, const UInt32 idx){
if ( idx >= v->used )
exitAtError("Vector","Array out of bounds");
return (void*)v->arr[idx];
}
而不是返回 const void * ,而是返回 void * 。我的想法是在内部,我想确保我不会更改指向的数据,但我不关心向量之外的数据会发生什么。
这被认为是对const的正确使用吗?我认为在一个地方将数据声明为const是可以的,同时在其他地方将其变为可变。在阅读了许多声称永远不会抛弃常数的教条文章之后,我不确定,如果它被丢弃,那么使用const是不合适的。
答案 0 :(得分:2)
我想'保证'向量不会改变其内容
这是C.数据结构没有行为。您可以定义矢量数据结构,以便最终指向的数据不能通过向量进行修改,这就是您所做的。当然,这有其含义。
我不知道它是否被认为是“过度使用”我的常量正确性,但我尝试使用我的访问者/修饰符维护const正确性:
如果您要打扰const
,那么请务必严格遵守const
- 正确性。否则,没有多大意义。
当我从向量中返回一个元素时,它是一个指向用户数据的指针,所以我让用户通过丢弃内部数组中的常量来修改指向的数据。
不。你吹了它。 const
- 正确性需要全部或全部才有价值。
通过丢弃const
,您违反了Vector
类型与其用户签订的合同,允许通过实例修改指向的值。间接地,确定,但这没关系。此外,这可能导致更广泛地违反const
正确性 - 例如,假设输入到您的向量中的数据首先是const
。然后将它们存储在您的数据结构中就可以了,但是您提供的功能可以允许它们被修改(或者至少可以尝试这样做)。
您可以考虑使用不透明的数据结构而不是const
- 限定成员以防止通过向量直接访问元素。但最终,const-correctness将需要单独的数据结构和函数,用于包含const
数据的向量和包含非const
数据的向量。
答案 1 :(得分:1)
我认为这是个坏主意,因为它允许在没有警告的情况下写入const对象。例如:
const int x = 5;
vector_add(&v, &x);
int *p = vector_get(&v, 0);
*p = 6; // oops
相反,请返回const void *
。然后你可以让调用者决定何时抛弃const。
你可能最终会有两个版本的向量,一个持有void *
,另一个持有const void *
。
答案 2 :(得分:1)
虽然其他答案在有限的const-correctness透视图中是正确的,但您应该注意,在C中,一旦指针进入此向量,就无法知道数据是否是[im]可变的。在这种情况下,vector不应该关心它,并且总是接受并返回非const指针。如果有人想在那里传递const指针,那么他将会在执行get()时进行转换并注意取消。用户有责任恢复初始存储语义,因为他 知道它。
你在这里的实际主张是你永远不会取消引用指针,但不是它是const。只需在docs中写一下。