在C ++中,它是可能的 在堆上分配一个const对象:
const Class* object = new const Class();
const_cast<Class*>( object )->NonConstMethod(); // UB
因此,写入对象的尝试将是UB。
我不知道这样的对象将如何与未声明的堆分配对象不同 const
:
const Class* object = new Class();
我的意思是当我在堆栈上分配一个对象时,它会去 自动存储 这是特定于实现的,因此可能存在一些允许分配的特定于实现的方法 const
对象以某种特殊的方式在写入对象时会产生UB。
然而每当我使用时 new
编译器需要发出 operator new()
函数invokation和该函数不可能做任何不同的事情 - 它只是以统一的方式分配内存,无论是否存在 const
在我的代码中。
怎么样? const
堆分配的对象不同于非const
一,如果我尝试修改它,未定义的行为怎么可能?
没有区别 物体。使用的变量的(编译时)类型有所不同 参考 到记忆区。
这只是语义摩擦:变量不同,数据位使用的实际内存是const / volatile不可知的。
对于一个非常 有趣和启发 描述类似语义摩擦的故事,请参阅Eric Lippert撰写的这一史上最喜欢的答案:
关于未定义的行为
以非const方式处理const数据可能会导致Undefined Behavior,因为允许编译器根据 知识 const变量不会改变1。改变它(例如通过 const_cast<>
)可能导致错误的结果,因为编译器的假设被积极否定。
1 注意 volatile
在const变量可以同时修改的情况下可以提供帮助。你可以看到如何 const
是一个'本地' 不会/不会碰 promis,而 volatile
说: '不要假设这不会改变,即使它没有被写入此代码段'。
`
它是不同的,因为创建的对象具有不同的类型(const Class
而不仅仅是 Class
),它是未定义的行为,因为标准是这样说的。
那是短版本。没有理由。 (如果有的话,反过来就是真的。没有理由让某些东西成为UB。UB是默认状态。只有当有某种原因得到明确的定义时才会出现这种情况)
至于它意味着什么 在实践中,或者如果将对象视为非const,它是否真的会导致问题,硬件不太可能做任何不同的事情。 const对象显然不会写入某种只读内存(因为这是不可能的),并且一旦分配了对象,它所在的内存页面可能不会被标记为只读。
但是允许编译器 承担 该对象是const。因此,如果保证对象不变,它可以以合法的方式优化或转换代码,但如果对象在中途被修改则会中断。
它实际上并不是关于对象如何存储在硬件中。 Const或没有const很少会对硬件级别产生影响。但它在类型系统中有所不同,它对编译器如何转换代码产生了影响。
如果你告诉编译器一个对象是const,那么编译器会相信你,并在假设对象是const的情况下生成代码。
使用当前的编译器,没有技术差异。未定义的行为包括奇迹般的工作。
我朦胧地记得,有一个建议让const限定的构造函数允许特殊的大小写实例 const
施工后立即;这将是有用的,例如对于字符串类,如果它们不需要期望字符串增长,它将分配更少的内存。
它依赖于实现,但它可能没有任何不同。它 可以 被修改。但编译器会拒绝尝试的代码。
const
更多的是拒绝编译修改对象的代码,而不是实际上无法通过任何方式进行修改。编译器的一个注释是“不要让我试图错误地改变它”。
const和非const对象之间没有任何区别。在你的例子中也没有未定义的行为。您期望UB是什么?通过调用非const函数,您将获得您期望的行为。
让我提醒你,可以声明一些字段 易变的 这样对象就不是整体的const。没有提到你甚至可以在syuch中滥用编译器不会意识到你的成员函数的具体非常量:
class A {
public:
A() : value_(0) {}
void abuse() const { const_cast<A*>(this)->value_ = 1 ; }
int value_;
};
void test() {
const A a;
std::cout << a.value_ << std::endl;
a.abuse() ;
std::cout << a.value_ << std::endl;
}
我们可能会得到UB。