Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 引用类型的数据成员提供;“漏洞”;关于常量正确性_C++_Class_Reference_Constants - Fatal编程技术网

C++ 引用类型的数据成员提供;“漏洞”;关于常量正确性

C++ 引用类型的数据成员提供;“漏洞”;关于常量正确性,c++,class,reference,constants,C++,Class,Reference,Constants,我最近偶然发现了以下关于常量正确性的“漏洞”: struct Inner { int field = 0; void Modify() { field++; } }; struct Outer { Inner inner; }; class MyClass { public: Outer outer; Inner& inner; // refers to outer.inner, for convenience MyClass() : inner

我最近偶然发现了以下关于常量正确性的“漏洞”:

struct Inner {
  int field = 0;
  void Modify() {
    field++;
  }
};

struct Outer {
  Inner inner;
};

class MyClass {
public:
  Outer outer;
  Inner& inner; // refers to outer.inner, for convenience

  MyClass() : inner(outer.inner) {}

  void ConstMethod() const {
    inner.Modify();  // oops; compiles
  }
};
似乎还可以利用此漏洞修改声明为
const
的对象,我认为这是未定义的行为:

int main() {
    const MyClass myclass;
    std::cout << myclass.outer.inner.field << "\n";  // prints 0
    myclass.ConstMethod();
    std::cout << myclass.outer.inner.field << "\n";  // prints 1
}
intmain(){
const MyClass MyClass;

std::cout这不是代码中的错误,请记住const指的是声明器的最里面的元素。基本上,const on const方法进行引用:

Inner& const inner;
当然,这不会产生任何真正的区别,因为引用无法重新绑定。考虑使用指针执行相同的操作,您会发现内部仍然可以修改。如果是:

Inner * const inner;
您可以调用internal->Modify()。

const
对象是未定义的行为,而代码段确实做到了这一点

程序不是格式错误(这将需要编译错误),因为在初始化
内部
时,cv限定符尚未生效

从编译器的角度来看,发出警告需要它分析通向
internal.Modify()
的所有代码路径,并证明
internal
必须引用
const
对象,这在一般情况下是不可能的


最好的建议是不要使用内部指针/引用,这无论如何都是有害的。

这不应该是未定义的行为。是的,
myclass.outer
被视为
const
inside
myclass::ConstMethod()const
,但它并不是以
const
的形式出现的,因此应该可以通过非
const
引用安全地修改它。当然,这样做可能会让代码的读者和/或用户感到惊讶,所以您应该尽量避免这种情况

这类似于

int x = 5;
int * xPtr = &x;
const int * constXPtr = &x;
其中
constXPtr
的存在不会(也不应该)阻止人们通过
xPtr
修改
x


值得注意的是,这种别名可能会阻止许多潜在的编译器优化。

如果打开警告,您对此有何了解?我实际上并不认为这是未定义的,只是不可取。它基于一个简单的事实,即在构造函数和析构函数中,
const
对象始终被视为非const对象。是的,您可以使用它来绕过常量正确性规则,而无需强制转换。这不是一个答案,而是有助于防止出现这种情况的东西:正如我在下面指出的,相关的问题是
myclass.internal
是否是“首次创建的”作为
const
。在
MyClass
的定义中,它不是
const
,所以我真的不知道!我知道它为什么要编译-这不是问题所在。问题是代码是否调用了未定义的行为,以及是否可以在编译时修改语言规则来捕获它。但是
MyClass.inner
不是
const
——它只是
MyClass::ConstMethod()const
中的
const
。该页面的关键引用(加上重点):“首次创建对象时,使用的cv限定符……确定对象的常量或波动性…”哎呀,错过了
myclass
本身被声明为
const
。但不知道如何修复我造成的损坏。对不起,
myclass.outer
在“首次创建”时被认为是
const
,现在还不完全清楚这就是相关的问题。@JoshuaGreen子对象显然是对象的一部分,否则你可以对一个类做任何你想做的事情。请阅读,如果你仍然不相信的话。Oops。从某种意义上说,上面的信息很有用,但我刚刚注意到OP将
myclass
声明为
const
。因此,这样做了es确实看起来像是类型系统中的一个不幸的漏洞,创建了一个
const
对象,同时将一个非
const
引用绑定到它。现在还不完全清楚
myclass.outer
在“首次创建”时是否被认为是
const
,这是相关的问题。