据我所知,具有const
在C ++方法意味着对象是只读的通过的方法,但它仍然可以改变否则。
但是,此代码显然通过改变一个物体const
(通过参照即const
方法)。
这是法律的代码在C ++?
如果是这样的:是不是打破了const
类型系统的-ness? 为什么/为什么不呢?
如果没有:为什么不呢?
注1:我已编辑的例子一点,这样的答案可能是指过去的一些例子。
编辑2:显然,你甚至不需要C ++ 11,所以我删除了依赖。
#include <iostream>
using namespace std;
struct DoBadThings { int *p; void oops() const { ++*p; } };
struct BreakConst
{
int n;
DoBadThings bad;
BreakConst() { n = 0; bad.p = &n; }
void oops() const { bad.oops(); } // can't change itself... or can it?
};
int main()
{
const BreakConst bc;
cout << bc.n << endl; // 0
bc.oops(); // O:)
cout << bc.n << endl; // 1
return 0;
}
更新:
我已经迁移的lambda来构造函数的初始化列表,因为这样做可以让我随后说const BreakConst bc;
,其中-因为bc
本身现在是const的(而不是仅仅指针) -似乎暗示( 由斯特劳斯 ),修改bc
在施工后任何方式应该导致未定义的行为,即使构造函数和调用者将有没办法知道这没有看到对方的定义。
的糟糕()方法不允许改变对象的常量性。 此外,它不这样做。 它的匿名函数,做它。 这个匿名功能不在对象的上下文,但是在main()方法被允许修改对象的上下文中。
您的匿名函数不改变糟糕()(其被定义为常量,因此不能被改变),并且还以任何方式导出从这个这个指针一些非const变量的这个指针。 本身不具有任何此指针。 它只是忽略了这个指针和改变主上下文的BC变量(如参数类型的传递给你的闭合)。 这个变量不常量,因此可以改变。 您还可以通过任何匿名函数变化一个完全无关的对象。 此函数不知道,它改变存储它的对象。
如果你将它声明为
const BreakConst bc = ...
然后主要功能也将处理它为const对象,无法改变它。
编辑: 换句话说:const属性绑定到混凝土-1-值(基准)访问的对象。 它不绑定到对象本身。
你的代码是正确的,因为你不使用const参考修改对象 。 拉姆达函数使用完全不同的参考,这恰好是指向同一个对象。
在一般情况下,这种情况下不颠覆式系统,因为在C ++类型系统没有正式保证,你不能修改const对象或常量引用。 然而,const对象的修饰是未定义的行为。
从[7.1.6.1]的cv修饰符 :
的指针或引用到CV-合格音响ED型不必实际上指向或引用的cv-合格音响编对象,但是,如果它确实它被处理; 一个const-合格音响ED访问路径不能被用来修改即使引用的对象是一个非const对象的对象,并且可以是通过一些其它访问路径MODI音响编辑。
除了任何类成员声明可变(7.1.1)可以是MODI音响版,任何企图其寿命(3.8)的结果中理解过程音响奈德行为期间修改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;
}
这不是C ++ 11,但不一样的:一点是常量不是传递 。
callinc()
不改变自身a
和incval
不会改变b
。 请注意,在main
,你甚至可以声明const A a(b);
代替A a(b);
一切编译相同。
此作品从几十年来,和你的样品中,你只是在做相同的:只需您更换B级与拉姆达。
编辑
改变的主要()来反映意见。
问题是逻辑常量与按位常量之一。 编译器不知道你的程序的逻辑含义任何东西,只有强制执行按位常量。 它是由你来实现逻辑常量。 这意味着,在情况下,像你展示,如果指向存储在逻辑上是对象的一部分,你应该从一个const函数修改它避免,即使编译器将让你(因为它不是按位图像的一部分对象的)。 这也意味着,如果对象的按位图像的一部分,不是(例如嵌入式的引用计数,或缓存值)对象的逻辑值的一部分,你把它mutable
,甚至抛弃常量,在案件在那里你修改,而不会修改对象的逻辑值。
const的功能仅仅是有助于防止意外的误操作。 它的目的不是要阻止专用软件的黑客。 这是一样的private和protected成员,别人随时都可以沿着存储器访问类的内部对象和增量的地址,也没有办法阻止它。
所以,是的,你可以避开常量。 如果不出意外,你可以简单地改变对象在内存的水平,但并不意味着常量被打破了。