带有指针的结构的 const 正确性

Posted

技术标签:

【中文标题】带有指针的结构的 const 正确性【英文标题】:const correctness for structs with pointers 【发布时间】:2012-11-01 16:36:12 【问题描述】:

我有一个包含一些指针的结构。我希望这些的价值是不可修改的。但是简单地写 const infront 并不会使结构成员不可变

typedef struct
  int *x;
  int *y;
point;

void get(const  point *p,int x, int y)
  p->x[0]=x;//<- this should not be allowed
  p->y[0]=y;//<- this should not be allowed

谁能指出我正确的方向。

编辑:

因此似乎没有简单的方法可以使用函数原型来告诉属于该结构的所有内容都应该是不可修改的

【问题讨论】:

你想要什么不可修改?指向ints?然后const int *x; 表示您不能通过该指针修改指向的值。指针?然后int * const x; 禁止修改指针。 如果我的 int *x, 是一个数组,那么我希望这个数组中的值是不可修改的。 那么你需要在结构定义中const int *x;。请注意,数组中的值仍然可以通过其他指针进行修改(如果x 指向const int arr[3] = 15, 7, 3 ; 左右的元素,则可能会调用未定义的行为)。 int *x 不是一个数组,它是一个指针。如果您声明了int x[20],那么该数组将成为consted 区域的一部分。但是x 是一个指针,它的constness 独立于p 之一。 您的编辑注释是错误的,因为const 正是这样做的:它表明属于struct 的所有内容都没有被该函数修改。您的想法的错误是混淆了 p 指向的区域以及 p->x 和 p->y 指向的区域,它们不是结构的一部分。看看我下面的ascii art,你的结构只是画出来的部分,其余的都是不同的。 【参考方案1】:

你可以通过定义一个 const 点类型和一个可变点类型来做到这一点而不需要类型转换,然后使用一个透明的联合:

typedef struct
    const int *  x;
    const int *  y;
 const_point;

typedef struct
    int *  x;
    int *  y;
 mutable_point;

typedef union __attribute__((__transparent_union__)) 
    const_point cpoint;
    mutable_point point;
 point;

然后,您使用 point 或 const_point 类型(绝不是 mutable_point 类型)声明函数参数。

point 类型对象将透明地转换为 const_point 类型,但不是相反。 这使您可以拥有更高程度的类型安全性。

请参阅此处以获取 gcc 中的示例:http://toves.freeshell.org/xueg/

请注意,我检查的最后一个 C++ 版本不支持透明联合(不确定最新的 C++ 标准),因此您可能会遇到可移植性问题。

它还可以使代码更难阅读和维护,尤其是当你有更复杂的结构时。 例如:您可能具有 x 或 y 为 const 的点类型,或者您可能需要将点结构嵌入到另一个结构中,例如矩形,您可能需要根据它们的 constness 为多种类型定义多个结构。

总而言之,我不确定这是否总是值得额外的麻烦。

【讨论】:

如果您喜欢使用引用以便可以使用右值实例化它(因为您可以将右值与常量引用一起使用),那么这可能是值得的。这可能是它似乎对我非常有用的唯一情况。【参考方案2】:

如果我正确理解您的问题,您希望将整个 struct 对象的 constness 自动传播到该 struct 成员指向的对象。 IE。如果 struct 对象不是 const,则数组应该是可修改的,而如果 struct 对象是 const,则数组不应该是可修改的。

如果是这样,那么很遗憾,这在 C 语言中是无法实现的。

在 C++ 中,可以通过强制用户使用访问器成员函数来访问数据成员(而不是直接访问数据成员)来完成。但在 C 语言中它根本无法完成。

【讨论】:

【参考方案3】:

解释你需要建立什么,当你写

point str;

point *p=&str;

这里 p 是一个指向 str 的指针,它的类型是 point

当你声明它为 const 时,就意味着 p 是一个常量指针。这并不限制结构可能包含的指针。

如果您希望const 应用于结构内部,则必须将结构内部的指针也定义为 const

typedef struct
   const int *  x;
   const int *  y;
point;

再次强调我的观点,将参数声明为

    void get(point * const  p,int x, int y) 
   //Constant Pointer ( *to prevent p from pointing to anything else*)

    //    AND

   //Make the pointers inside point structure constant
   //( *to prevent the int pointers x & y from pointing to anything else*)

如果它指向的结构也是 const 使用

      void get(const point * const p, int x, int y)
     //Constant Pointer to constant structure 

【讨论】:

如果我的结构成员被声明为 const,我如何在程序开始时在其中输入值。 通过类型转换为非 const 指针。 (int*)(p-&gt;x) = &amp;whatever。虽然它看起来可能会破坏constness 的目的。在您希望确保对结构的更改仅在受控的独特位置进行的大型项目中非常有用。 由于指针的内容是常量,所以在声明的时候应该初始化。 IMO 没有意义 consting 指针本身(或任何其他函数参数)。指向区域的常量很重要,它告诉读者这个指针没有副作用,但是指针本身的常量并没有传达有用的信息,对编译器和程序员都没有。 @PatrickSchlüter 它只是防止在函数内意外重新分配指针。例如函数顶部的if(myStruct = NULL) 对于任何简单阅读代码的人来说都是一个非常模糊的错误。【参考方案4】:

那是因为你改变了另一个指针指向的内存内容,而不是p

p 指向一个包含 2 个指向 int 的指针的结构。您不会更改p 指向的内存,而是另一个内存区域。所以编译器对此很好。

       +----------+
p ->   |    x     |  -> wherever  
       +----------+
       |    y     |  -> another place in memory
       +----------+

constness od p 不可继承。如果你写了p-&gt;a = array;,那么编译器就会抱怨。 const 只是一个合同,表明您不会通过该指针更改内存。

【讨论】:

以上是关于带有指针的结构的 const 正确性的主要内容,如果未能解决你的问题,请参考以下文章

正确使用 const_cast 与第三方库

C++基础3(函数指针结构体)

C++基础3(函数指针结构体)

函数参数中的 struct 关键字和 const 正确性

C和指针 第10章 结构和联合

为啥很少有人输入 const 正确的代码? const 正确的代码会编译得更好/更快吗? [关闭]