如果更改 const 对象是未定义的行为,那么构造函数和析构函数如何通过写访问进行操作?

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

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

问题描述

C++ 标准规定,修改最初声明为 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?

推荐答案

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

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

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

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.

还有 12.4/2 析构函数":

And 12.4/2 "Destructors":

可以为 constvolatileconst volatile 对象调用析构函数.... constvolatile 语义 (7.1.5.1) 不适用于正在销毁的对象.一旦最派生对象 (1.8) 的析构函数启动,这种语义就会停止生效.

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.

作为背景,Stroustrup 在《C++ 的设计与演进》(13.3.2 const 的定义的细化)中说:

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

为了确保某些(但不是全部)const 对象可以放入只读内存 (ROM),我采用了任何具有构造函数的对象(即需要运行时初始化)的规则) 不能放在 ROM 中,但其他 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.

...

声明为 const 的对象从构造函数完成到其析构函数开始被认为是不可变的.在这些点之间写入对象的结果被视为未定义.

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.

最初设计 const 时,我记得我曾争论过理想的 const 将是一个在构造函数运行之前可写的对象,然后在某些硬件中变为只读魔法,最后在进入析构函数时再次变得可写.可以想象一种实际上以这种方式工作的标记架构.如果有人可以写入对象定义的 const,这样的实现会导致运行时错误.另一方面,有人可以写入一个未定义的对象 const 已作为 const 引用或指针传递.在这两种情况下,用户都必须首先抛弃 const.这种观点的含义是,对于最初定义的对象 const 丢弃 const 然后写入它充其量是未定义的,而对一个对象做同样的事情最初没有定义 const 是合法且定义明确的.

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.

请注意,通过对规则的这种改进,const 的含义不再取决于类型是否具有构造函数;原则上,他们都这样做.现在任何声明为 const 的对象都可以放在 ROM 中,放在代码段中,受访问控制等保护,以确保它在收到初始值后不会发生变异.然而,这种保护不是必需的,因为目前的系统通常不能保护每个 const 免受各种形式的损坏.

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 对象是未定义的行为,那么构造函数和析构函数如何通过写访问进行操作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:如果更改 const 对象是未定义的行为,那么构造函数和析构函数如何通过写访问进行操作?