用于临时更改对象的 const 方法

Posted

技术标签:

【中文标题】用于临时更改对象的 const 方法【英文标题】:Const method to temporarily change object 【发布时间】:2012-12-06 13:04:36 【问题描述】:

我有一个类Reader,它提供对二进制文件的访问以对其执行读取操作。

此文件包含同一文件中的多个偏移列表,可在其中找到数据。这意味着,要获取某些数据段,必须从某个位置读取偏移量,然后跳转到该偏移量,再次读取偏移量,然后跳转到那里,等等,直到最终到达实际数据。

该类维护一个阅读位置,每次调用类似的方法时都会调整该位置

// reads 4 bytes and advances the position by 4 bytes
uint32 Reader::readOffset()  /* */  

// moves the position to offset
void Reader::jumpTo(uint32 offset)  /* */ 

这些方法显然不能是const,因为它们正在移动阅读位置。

为了方便在文件的多个级别之间导航,该类提供了一个堆栈,可以根据需要在其中推送和弹出偏移量:

uint32 someOffset = reader.readOffset();
reader.pushOffset(); // remember position
reader.jumpTo(someOffset); // do something on another position
reader.popOffset(); // go back to where we were before

那些 push/pop 方法也不能是 const,因为它们会改变偏移堆栈。

现在的问题在于便利方法,它们应该从文件中的内部已知位置提取数据。无论当前阅读位置如何,它们都必须工作,并且不应触摸它。按照设计,它们应该是const,但这不起作用:

uint32 Reader::readSomeDataFromKnownLocation() const

    pushOffset();

    jumpTo(1234ul);
    uint32 data = readData();

    popOffset();

    return data;

确实知道此方法将使对象保持与调用前相同的状态,但我仍然无法做到const,因为我在其中使用的每个方法都是非const

所以,我的问题是,当必须在“按设计”const 方法中临时更改对象的状态时,最好的方法是什么?

我想过const_cast<Reader*>(this),但这似乎是一种骇人听闻的方法。或者您认为在这种情况下这样做是否合理?

【问题讨论】:

如果它是 const 设计的,那么它是一个常量,不应该改变。如果它会被改变,那么它就不是一个常数。 变化只是在内部暂时发生。该方法将确保返回的最终对象状态与用户调用它之前的状态“相同”。这就是我想通过标记const来展示的内容。 不正确,您无法验证它是否会发生。在您跳转并从文件中读取之后,代码(或线程)可能会立即失败。那么对象本身就处于不同的状态(想想多线程,一个邪恶的线程杀死了其他线程)。 确实如此。所以你认为说它是const 只是一些模糊的假设,并不真正符合 const 正确性?是否最好将其保留为非常量并且仅记录对象的状态不会(不应该)受到影响? 【参考方案1】:

您可以将位置字段设为mutable,然后将您的逻辑只读方法标记为const

如果您想在公共 API 中保留 pushOffsetpopOffset 方法,您应该引入 const 的私有版本,并在您的 readSomeDataFromKnownLocation 方法中使用私有版本。

【讨论】:

我无法创建位置mutable 和读取方法const,因为它们会根据当前位置为用户产生不同的结果,而且它们会更改后续调用的潜在结果。跨度> @Dienes 我认为您的读取方法正在读取完成后恢复位置指示器。如果是这样,他们如何更改后续调用? 读取方法有两种:一种是每次调用都会提前读取位置,另一种只是暂时移动读取位置以检索数据,然后在返回之前恢复旧位置。后者依赖于前者。 @Dienes 然后要使后者成为 const,您需要引入前者的私有 const 版本。有可能——我怀疑你会发现拥有大多数方法的两个版本是否值得拥有 readSpecificData() 方法 const。 我明白了。因此,总而言之,将其保留为非const 并传达它不会改变当前阅读位置是可以的。谢谢。

以上是关于用于临时更改对象的 const 方法的主要内容,如果未能解决你的问题,请参考以下文章

这是在 React 中更改对象状态变量的最安全、最正确的方法吗?

在普通 for 循环中更改 QVector 的对象

C++ 如何处理 const 标记的通过引用传递的类,这些类不是直接更改而是从另一端更改的? [复制]

临时更改与永久更改主机名

指向从未被设为 const 的 const 对象的 C++ 指针 [重复]

临时对象最初是 const 吗?