这是否适合在C中使用const限定符?

时间:2015-06-18 21:39:19

标签: c const

我在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是不合适的。

3 个答案:

答案 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中写一下。