为什么“具有const成员的结构”类型的指针不能指向“具有非const成员的结构”?

时间:2018-10-05 09:08:30

标签: c++ pointers const const-pointer

此代码无法编译:

struct s_t {
    int a;
};

struct c_s_t {
    const int a;
};

s_t s;
c_s_t *c_s = &s;
ibug@ubuntu:~ $ g++ -fsyntax-only t.cpp
t.cpp:10:15: error: cannot convert ‘s_t*’ to ‘c_s_t*’ in initialization
 c_s_t *c_s = &s;
               ^

然而,这个版本可以完美编译:

int a, *pa = &a, **ppa = &pa, ***pppa = &ppa;
const int * const * const * const cpcpcpa = pppa;

我知道在 any 级别上具有更高CV资格的指针可以在任何级别上指向具有较低CV资格的对象,但是为什么结构不相同?


上面的问题陈述是一个更复杂问题的MCVE,其中我的朋友正在尝试在t_s_t<T>t_s_t<const T>之间转换指针,其中t_s_t是一个模板结构类型,其中一个模板参数typename,而T是任意类型。

4 个答案:

答案 0 :(得分:4)

原因是s_tc_s_t是不同的类型。

即使您将c_s_t定义为:

struct c_s_t {
    int a; // <-- non-const!
};

然后:

s_t s;
c_s_t *c_s = &s;

它仍然无法正常工作。

答案 1 :(得分:1)

类型错误是您的问题,您只是在尝试分配错误的类型。

这将起作用:

s_t s;
s_t *c_s = &s; //types are matching

答案 2 :(得分:0)

这两个是不同的结构,它们是不可转换的。他们具有相同的成员这一事实无关紧要,即使您从const中删除了c_s_t,也不会改变任何内容。

您的其他示例可行,因为您要将修饰符应用于一种类型。例如,这是完全合法的:

struct s_t {
    int a;
};

s_t s;
const s_t const* cs = &s;

答案 3 :(得分:0)

  

我了解在任何级别上具有更高CV资格的指针都可以指向在任何级别上具有更低CV资格的对象

实际上并非如此,至少不是您所描述的那样。只能任意添加最高的CV限定词(当然,指针本身也可以添加CV限定词!),在C和C ++中都是这种情况。

以下是“任意级别”概念的反例,直接取自当前标准草案中的[conv.qual/3]

  

[注意::如果程序可以将类型为T**的指针分配给类型为const T**的指针(也就是说,如果允许下面的第1行),程序可能会无意间修改const对象(就像在第2行上完成的一样)。例如,

int main() {
  const char c = 'c';
  char* pc;
  const char** pcc = &pc;       // #1: not allowed
  *pcc = &c;
  *pc = 'C';                    // #2: modifies a const object
}
     

—注释]

无论如何,然后您问:

  

但是结构为何不一样?

当然,您可以将const T*指向T,但这不是您要执行的操作。此规则不适用于递归。类可以容纳一个以上的成员,因此您的方法通常无法正常使用(单成员类不需要特殊的规则)。

在这种特殊情况下,这两个类在布局上是兼容的,因此我希望reinterpret_cast在大多数情况下似乎都起作用:

struct s_t {
    int a;
};

struct c_s_t {
    const int a;
};

int main()
{
   s_t s;
   c_s_t *c_s = reinterpret_cast<c_s_t*>(&s);
}

live demo

但是,看来aliasing on the merits of layout-compatibility is not actually well-defined似乎使您最好重新考虑设计。

tl; dr:不同的类型是不同的类型。