4

我有一些代码是在不考虑 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);
    ...
};
4

4 回答 4

2

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

于 2013-04-22T12:47:05.433 回答
1

实际上,恕我直言,复制构造函数应该始终将 const 引用作为其参数。

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

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

X const test;
X new_x(test);

我无法想象为什么有人应该排除 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 正确,你可能需要检查整个类。它只会影响您的课堂实施。因为我不知道外部代码应该依赖类成员函数的“非常量”的情况。除非我的示例中的任何公共成员函数返回非常量引用。

以下代码段将按预期进行。

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; }。为了安全起见,您当然可以同时提供两者。

于 2013-04-22T13:19:29.500 回答
0

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
}

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

于 2013-04-22T13:52:27.727 回答
0

由于您正在更改具有复制构造函数的类,因此我假设您可以检查复制构造函数代码。如果您可以进行此更改并且复制构造函数没有给出编译器错误,那么您可能很好。要考虑的一种情况是复制赋值运算符的作用,因为不能保证在优化代码中会调用它。因此,还要确保您的复制分配将与 const 参数一起使用。

于 2013-04-22T12:44:28.893 回答