添加const正确性

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);
    ...
};

我可以看到我的问题被稍微误解了。我不是在问如何重写复制构造函数,我的问题是,在使用X类的大量代码的情况下这样做是否有任何危险。这些代码是由一个显然对const一无所知并且正在使用一个不关心的编译器编写的。现在在移植到一个新的编译器时,我留下了不能编译的代码和不能在STL中使用的类。 - john
4个回答

2

对于复制构造函数,我不这么认为。但请注意,通常情况下,声明const可能会影响调用哪个方法。我能想到的唯一例子是在数组重载中 - 参见例如这个问题


1

实际上,我认为复制构造函数应该始终以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; } 将失败。 当然,为了安全起见,您可以同时提供两个。

0

djechlin在他的回答中提出了一个重要观点,尽管有些不清楚,所以我会尝试更好地解释。

对象或引用的const性质会影响重载决议。例如,如果您有一个具有基于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
}

现在,如果其中一个重载具有副作用而另一个没有,那么在更改签名后,您将获得不同的行为,尽管程序编译良好。


0

由于您正在更改具有复制构造函数的类,我假设您可以检查复制构造函数的代码。如果您可以进行此更改并且复制构造函数不会产生编译器错误,则可能很好。要考虑的一个角落案例是复制赋值运算符的操作,因为无法保证哪个操作将被调用,特别是在优化代码中。因此,请确保您的复制赋值运算符能够使用const参数正常工作。


1
你能举个例子,让你无法确定是调用复制构造函数还是赋值运算符的情况吗? - Agentlien
这是我在eliding方面提出的一个问题。https://dev59.com/0mDVa4cB1Zd3GeqPc2Og - rerun
就我所知,这只意味着您无法确定副本是否会被省略。无论如何,我没有看到在您(有理由)期望复制构造函数或反之亦然的情况下会调用赋值运算符的情况。 - Agentlien

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