增加const正确性

Adding const correctness

本文关键字:正确性 const 增加      更新时间:2023-10-16

我有一些没有考虑const正确性的代码。在任何情况下,

class X
{
public:
    X(X& rhs); // does not modify rhs
    ...
};

class X
{
public:
    X(const X& rhs);
    ...
};

会改变现有程序的行为吗?我知道这个变化将允许代码目前不编译编译,但我感兴趣的是,如果有任何情况下,已经编译的代码会改变它的行为。

类似的问题,做这样的改变有什么好处吗?

class X
{
public:
    X(X& rhs); // does not modify rhs
    X(const X& rhs);
    ...
};

对于复制构造函数,我不这么认为。但是请注意,一般来说,是的,const的声明会影响调用哪个方法。唯一能想到的例子就是数组重载——比如这个问题。

实际上,复制构造函数应该始终接受const引用作为实参。

X(X& rhs) { } // does not modify rhs

不允许复制const对象,因此下面的代码无法编译。虽然非const对象可以作为const实参,但反过来是不可能的

X const test;
X new_x(test);

我无法想象为什么有人要禁止复制const对象。

关于你想要做的改变:复制构造函数是否依赖于任何定义为非const的X成员函数?

这将像魅力一样工作,但允许复制const对象:

class X
{
private:
  int a;
public:
  X(X &rhs) { a = rhs.value(); } 
  int& value (void) { return a; }
};

下一个示例将无法编译,因为rhs是const,而value()不是const。

class X
{
private:
  int a;
public:
  X(X const &rhs) { a = rhs.value(); } 
  int& value (void) { return a; }
};

如果你想使你的类const正确,你可能需要检查整个类。它应该只影响你的类内实现。因为我不知道外部代码应该依赖于类成员函数的"非constness"的情况。除非像我的例子中那样,任何公共成员函数返回非const引用。

下面的代码片段可以达到预期的效果。

class X
{
private:
  int a;
public:
  X(int const &b) : a(b) { }
  X(X const &rhs) { a = rhs.value(); } 
  int const & value (void) const { return a; }
};

但是要注意,这将干扰任何代码,如:

X test(100);
test.value() = 12;

使用int& value (void) { return a; }可以工作,但使用int const & value (void) const { return a; }就失败了。当然,为了安全起见,您可以同时提供这两个选项。

由于您正在更改具有复制构造函数的类,我假设您可以检查复制构造函数代码。如果您可以进行此更改,并且复制构造函数不会给出编译器错误,那么您可能是好的。要考虑的一个常见情况是复制赋值操作符的作用,因为不能保证将调用哪个操作符,特别是在优化代码中。所以也要确保你的拷贝赋值能和const形参一起工作。

djechlin在他的回答中表达了一个重要的观点,尽管有些不清楚,所以我会尽量解释得更好。

对象或引用的常量影响重载解析。例如,如果一个对象的成员函数具有基于const的重载,则将选择不同的重载:

struct foo {
    void do_stuff();
    void do_stuff() const;
};
int main() {
    foo f;
    const foo& fr = f;
    f.do_stuff();   // calls non-const version
    fr.do_stuff();  // calls const version
}

现在,如果其中一个重载有副作用,而另一个没有,那么在更改签名后,您将得到不同的行为,假设(或者更确切地说,即使)程序编译良好。