常量正确性和硬件写入

5

假设我有以下成员函数:

void CFoo::regWrite( int addr, int data )
{
  reg_write( addr, data ); // driver call to e.g. write a firmware register
}

显然,调用这个函数不会修改被调用对象的内部状态。但是,它会改变任何这个Foo实例所代表的状态。

在这种情况下,Foo::regWrite(int addr, int data)应该是一个const函数吗?


CFoo类是否代表固件?(例如,固件状态是否可以视为对象状态?) - Krumelur
据我所知,一个既不改变其对象又不触及任何状态的方法被称为“纯函数”。从技术上讲,如果表示的对象是 CFoo 类的一部分,则不要将其作为 const 函数。如果它是全局定义的对象,则将其设置为 const 函数。 - Ancurio
2
假设CFoo有其他操作,那么是否会受到对regWrite的调用的影响?如果是,则它显然是状态的一部分;如果不是,则您应该问自己为什么它是类的一部分,而不是一个简单的自由函数,因为它既不获取也不设置与该对象相关的任何状态。 - PlasmaHH
4个回答

3
你需要决定对于类CFoo,“逻辑上的常量”是什么意思,这取决于该类的用途。
如果CFoo被视为“引用某些数据”,那么可能有意义通过const实例来修改该数据,在这种情况下,您的成员函数将是const。例如考虑其他引用某些数据的类型 - 您可以修改char * constconst std::unique_ptr<char>的引用对象。
如果CFoo被视为“拥有某些数据”,则可能有意义禁止通过const实例来修改该数据。例如考虑容器,其中元素在物理上不属于对象的一部分,但在逻辑上它们是“对象状态的一部分”。因此,vector::operator[]具有返回const T&而不是T&的const重载,insert成员函数是非const等。

1

对于一个类来说,“const”应该意味着什么由程序员定义。使用修饰符“mutable”,甚至可以在成员中拥有一个具有可变值的“const”对象。当涉及到硬件时,人们可能会将配置视为常量正确性的目标:只要配置不改变,对象就可以被视为常量。


1

这个问题有两种看法 - 优化角度和声明逻辑。哪一个更重要,由你决定。

优化

编辑:我做了一些错误的假设。似乎编译器实际上不能自由地进行以下优化,只有通过分析方法的主体以确保没有修改发生(即使在简单情况下也是如此)才会进行这些优化。

拥有这个const将允许编译器进行一些优化。它知道regWrite不会改变对象中的任何字段,因此如果它正在存储它们,则可以保留它们,并进行依赖于对象字段未被更改的类似优化。

当您制作这样的定义时,这真的是编译器所依赖的唯一事情,因此拥有这个const是可以的,并且理论上可以提高性能。

逻辑上讲得通

在一个const方法中进行破坏性的改变感觉不直观。程序员通常的直觉是只要我调用的是const方法,其他const方法的结果就不应该改变。如果你违反了这个不成文的契约,即使编译器没有问题,人们也会感到惊讶。

我不确定这里是否会违反这个契约 - 这将取决于这个类中的其他代码。然而,如果没有其他考虑因素(性能等),对于我来说,const主要是接口上的一个标记,表示“调用此方法不会改变此对象的状态”,对于“状态”的广义定义而言。

然而,这是模糊的领域,你可以自行决定什么是状态改变。如果你认为你的固件对象代表着内部的一个链接,那么写入寄存器并不会改变这个链接的任何内容,因此是const的。如果你认为它代表底层寄存器的状态,那么写入寄存器就是一种状态改变。


它知道regWrite函数不会更改对象中的任何字段 - 这是误导性的。编译器不能假设只因为成员函数是“const”就不修改任何数据成员。这种优化不符合C++标准。如果该函数可以内联,使得编译器能够看到函数实际执行的操作,则它可能推断出它不会修改任何数据成员。无论它是否能够推断出这一点,都不取决于函数是否为“const”,而是取决于其执行的操作。 - Steve Jessop
已验证。看来你是对的,我错误地假设编译器可以依赖于方法的“常量性”来保持对象不变。这是我的错误,我会进行编辑以更正。 - Jakub Wasilewski

1
如果您的类中有指向其他对象的指针,那么会出现类似的问题:您的const方法可以调用其他对象上的非const方法,从而修改它。
如果您将硬件视为类引用的某个其他对象,那么修改固件设置就是完全有效的(因为只更改了“引用”对象)。如果您希望您的类“表示”硬件(或其一部分),我建议不要将该方法标记为const
所以我认为这主要取决于您设计类的方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接