此代码是否破坏了C++;类型系统? < >我明白,在C++中使用 const 方法意味着一个对象是通过该方法只读的,但它可能仍然会发生变化。

此代码是否破坏了C++;类型系统? < >我明白,在C++中使用 const 方法意味着一个对象是通过该方法只读的,但它可能仍然会发生变化。,c++,constants,const-correctness,aliasing,C++,Constants,Const Correctness,Aliasing,但是,此代码显然通过const引用(即通过const方法)更改对象 这个代码是C++中合法的吗? 如果是:它是否破坏了类型系统的常数?为什么 若否,原因为何 注1:我对示例进行了一些编辑,因此答案可能是指较旧的示例。 编辑2:显然你甚至不需要C++11,所以我删除了这个依赖项。 #包括 使用名称空间std; 结构DoBadThings{int*p;void oops()const{++*p;}; 结构BreakConst { int n; 多巴德:事情不好; BreakConst(){n=0;错

但是,此代码显然通过
const
引用(即通过
const
方法)更改对象

<>这个代码是C++中合法的吗? 如果是:它是否破坏了类型系统的
常数?为什么

若否,原因为何

注1:我对示例进行了一些编辑,因此答案可能是指较旧的示例。 编辑2:显然你甚至不需要C++11,所以我删除了这个依赖项。
#包括
使用名称空间std;
结构DoBadThings{int*p;void oops()const{++*p;};
结构BreakConst
{
int n;
多巴德:事情不好;
BreakConst(){n=0;错误。p=&n;}
void oops()const{bad.oops();}//无法更改自身…或者可以吗?
};
int main()
{
康斯特布雷克康斯特bc;
cout不允许oops()方法更改对象的常量。此外,它也不允许更改。执行此操作的是您的匿名函数。此匿名函数不在对象的上下文中,而是在允许修改对象的main()方法的上下文中

您的匿名函数不会更改oops()的this指针(定义为常量,因此无法更改),也不会从此指针派生一些非常量变量。它本身没有任何this指针。它只是忽略this指针并更改主上下文的bc变量(这有点像是作为闭包的参数传递的)。此变量不是常量,因此可以更改。您也可以传递任何匿名函数来更改完全不相关的对象。此函数不知道,它正在更改存储它的对象

如果你愿意宣布它为

const BreakConst bc = ...
然后主函数也会将其作为常量对象处理,并且无法更改它

编辑:
换句话说:const属性绑定到具体的l值(参考)访问对象。它不绑定到对象本身。

您的代码是正确的,因为您不使用常量引用修改对象。。lambda函数使用完全不同的引用,恰好指向同一对象

在一般情况下,这种情况不会破坏类型系统,因为C++中的类型系统没有正式保证,不能修改const对象或const引用。但是const对象的修改是未定义的行为。 根据[7.1.6.1]cv限定符:

指向cv限定类型的指针或引用不需要实际指向 或引用cv限定对象,但视为符合条件;a 常量限定访问路径不能用于修改对象,即使 引用的对象是非常量对象,可以通过 其他一些访问路径

除任何声明为可变(7.1.1)的类成员可以修改外, 在常量对象的生存期(3.8)内修改该对象的任何尝试都会导致 在未定义的行为中


我已经看到了类似的东西。基本上你调用了一个成本函数,它调用了一些其他的东西,在不知道的情况下修改了对象

请考虑这一点:

#include <iostream>
using namespace std;

class B;

class A
{
    friend class B;
    B* pb;
    int val;
public:
    A(B& b); 
    void callinc() const;
    friend ostream& operator<<(ostream& s, const A& a)
    { return s << "A value is " << a.val; }
};

class B
{
    friend class A;
    A* pa;
public:
    void incval() const { ++pa->val; }
};

inline A::A(B& b) :pb(&b), val() { pb->pa = this; }
inline void A::callinc() const { pb->incval(); }


int main()
{
    B b;
    const A a(b);  // EDIT: WAS `A a(b)`
    cout << a << endl;
    a.callinc();
    cout << a << endl;
}
#包括
使用名称空间std;
乙级;;
甲级
{
B级朋友;
B*pb;
int-val;
公众:
A(食宿);;
无效callinc()常量;

friend ostream&operator问题是逻辑常量与按位常量的比较。编译器 对程序的逻辑意义一无所知,而且 只强制按位常量。由您来实现逻辑常量。 这意味着,在您展示的情况下,如果指向内存的 从逻辑上讲,作为对象的一部分,您应该避免在 const函数,即使编译器允许(因为它不是 这也可能意味着如果 对象的按位映像不是 对象(例如,嵌入的引用计数或缓存的值),则
可变的
,甚至丢弃常量,如果您在不使用
修改对象的逻辑值。

const功能仅帮助防止意外误用。它不是为了防止专用软件黑客攻击而设计的。它与私有和受保护的成员身份相同,有人可以始终获取对象的地址并沿内存递增以访问类内部,无法住手


因此,是的,您可以绕过const。如果没有其他内容,您只需在内存级别更改对象,但这并不意味着const已损坏。

这有点离题,但
void(void)
是一个不推荐使用的构造,因为
void()
从C++98和C99开始就做了同样的事情。@moshbear:我不知道是什么原因让我这么写的(向后兼容C还是什么的?!);修复了,谢谢。:-)我喜欢你的
O:)
smiley的双重含义是快乐的天使和惊骇的脸,这取决于你从哪个方向读它。你可以在这里找到更多的信息:(类似于人们不喜欢的问题:))这是我的问题,受此启发,它也不需要另一个结构;)常量对象?这是从哪里来的?我以为指针/引用就是常量。@Mehrdad:
const Foo f;
声明了一个常量对象,正如我在标准中引用的那样-常量引用被视为指向常量对象。@RafałRawicki:Hmm,这很有趣……那么你是说这是UB?我想我的问题是,为什么它是UB?(即,在代码的哪一部分,确切地说,我违反了什么?)我的回答是关于颠覆类型系统本身的问题。第二,你的代码样本没有使用const引用,因此它是正确的。这是一个很好的例子,说明了为什么
#include <iostream>
using namespace std;

class B;

class A
{
    friend class B;
    B* pb;
    int val;
public:
    A(B& b); 
    void callinc() const;
    friend ostream& operator<<(ostream& s, const A& a)
    { return s << "A value is " << a.val; }
};

class B
{
    friend class A;
    A* pa;
public:
    void incval() const { ++pa->val; }
};

inline A::A(B& b) :pb(&b), val() { pb->pa = this; }
inline void A::callinc() const { pb->incval(); }


int main()
{
    B b;
    const A a(b);  // EDIT: WAS `A a(b)`
    cout << a << endl;
    a.callinc();
    cout << a << endl;
}