如果更改const对象是未定义的行为,那么构造函数和析构函数如何使用写访问操作? [英] If changing a const object is undefined behavior then how do constructors and destructors operate with write access?

查看:159
本文介绍了如果更改const对象是未定义的行为,那么构造函数和析构函数如何使用写访问操作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++标准说,修改最初声明为 const 的对象是未定义的行为。

  class Class {
public:
Class(){更改(); }
〜Class(){Change(); }
void Change(){data = 0; }
private:
int data;
};

//以后:
const类对象;
//object.Change(); - 不会编译
const_cast< Class&>(object).Change(); //编译,但它是未定义的行为

我的意思是这里的构造函数和析构函数与调用代码完全相同,但是它们允许改变对象,调用者不允许 - 他运行到未定义的行为。

解决方案

p>

标准明确允许构造函数和析构函数处理 const 对象。从12.1 / 4构造函数:


可以为 const volatile const volatile 对象。 ... const volatile 语义(7.1.5.1)不适用于正在构建的对象。这种语义只有在最终派生对象(1.8)的构造函数结束时才会生效。


和12.4 / 2Destructors


一个析构函数可以被调用 const volatile const volatile 对象。 ... const volatile 语义(7.1.5.1)不适用于销毁对象。


作为背景,Stroustrup在Design和C ++的演变(13.3.2定义 const 的细化):


为了确保一些而不是所有的 const 对象可以放置只读存储器(ROM),我采用了规则,任何对象有一个构造函数是,需要运行时初始化)不能放在ROM中,但其他 const 对象可以。





被声明为 const 的对象从构造函数的完成直到其析构函数的开始都被认为是不可变的。



在最初设计 const 时,我记得认为理想的 const 将是一个可写的对象,直到构造函数运行,然后变成只读的一些硬件魔法,最后一旦进入析构函数变成可写。可以想象一个实际工作方式的标记架构。如果有人可以写一个定义 const 的对象,这样的实现会导致运行时错误。另一方面,有人可以写一个未定义的对象作为 const 引用或指针传递的 const 。在这两种情况下,用户必须首先丢弃 const 。这个视图的含义是,为最初定义的对象 const 抛出 const ,然后写入最好是未定义的,而对最初未定义的对象执行相同操作 const 是合法的并且定义良好。



请注意,随着规则的细化, const 的含义不取决于类型是否具有构造函数;在原则上,他们都做。任何声明为 const 的对象现在可以被放置在ROM中,被放置在代码段中,被访问控制等保护,以确保它在接收到它之后不会变异初始值。然而,不需要这种保护,因为当前的系统一般不能保护每个 const 不受每种形式的损坏。



C++ standard says that modifying an object originally declared const is undefined behavior. But then how do constructors and destructors operate?

class Class {
public:
    Class() { Change(); }
    ~Class() { Change(); }
    void Change() { data = 0; }
private:
    int data;
};

//later:
const Class object;
//object.Change(); - won't compile
const_cast<Class&>( object ).Change();// compiles, but it's undefined behavior

I mean here the constructor and destructor do exactly the same thing as the calling code, but they are allowed to change the object and the caller is not allowed - he runs into undefined behavior.

How is it supposed to work under an implementation and according to the standard?

解决方案

The standard explicitly allows constructors and destructors to deal with const objects. from 12.1/4 "Constructors":

A constructor can be invoked for a const, volatile or const volatile object. ... const and volatile semantics (7.1.5.1) are not applied on an object under construction. Such semantics only come into effect once the constructor for the most derived object (1.8) ends.

And 12.4/2 "Destructors":

A destructor can be invoked for a const, volatile or const volatile object. ... const and volatile semantics (7.1.5.1) are not applied on an object under destruction. Such semantics stop being into effect once the destructor for the most derived object (1.8) starts.

As background, Stroustrup says in "Design and Evolution of C++" (13.3.2 Refinement of the Defintion of const):

To ensure that some, but not all, const objects could be placed read-only memory (ROM), I adopted the rule that any object that has a constructor (that is, required runtime initialization) can't be place in ROM, but other const objects can.

...

An object declared const is considered immutable from the completion of the constructor until the start of its destructor. The result of a write to the object between those points is deemed undefined.

When originally designing const, I remember arguing that the ideal const would be an object that is writable until the constructor had run, then becomes read-only by some hardware magic, and finally upon the entry into the destructor becomes writable again. One could imagine a tagged architecture that actually worked this way. Such an implementation would cause a run-time error if someone could write to an object defined const. On the other hand, someone could write to an object not defined const that had been passed as a const reference or pointer. In both cases, the user would have to cast away const first. The implication of this view is that casting away const for an object that was originally defined const and then writing to it is at best undefined, whereas doing the same to an object that wasn't originally defined const is legal and well defined.

Note that with this refinement of the rules, the meaning of const doesn't depend on whether a type has a constructor or not; in principle, they all do. Any object declared const now may be placed in ROM, be placed in code segments, be protected by access control, etc., to ensure that it doesn't mutate after receiving its initial value. Such protection is not required, however, because current systems cannot in general protect every const from every form of corruption.

这篇关于如果更改const对象是未定义的行为,那么构造函数和析构函数如何使用写访问操作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆