在const成员不良实践或UB中修改const变量?

时间:2012-06-18 21:30:48

标签: c++

下面的代码是不良做法还是未定义的行为?本质上我调用const函数来修改未标记为可变的成员。链接到demo

致Mehrdad鼓励这个问题(他的问题Does this code subvert the C++ type system?)和大卫进行小型演示改进。

#include <iostream>
using namespace std;

struct BreakConst
{
    int v;
    int *p;
    BreakConst() { v = 0; p = &v; } 
    void break_stuff() const { ++*p; }
};
void f(const BreakConst& bc) {
    bc.break_stuff();
}

大多数答案基于的原始版本:

DavidRodríguez,jpalecek,Mehrdad回答 是的:这是“未定义的行为”

int main()
{
    const BreakConst bc;
    cout << bc.v << endl;   // 0
    bc.break_stuff();       // O:)
    cout << bc.v << endl;   // 1

    return 0;
}

新的替代问题:

Mehrdad回答 否:这不是“未定义的行为”

int main()
{
    BreakConst bc;
    cout << bc.v << endl;   // 0
    f(bc);                  // O:)
    cout << bc.v << endl;   // 1

    return 0;
}

结果:

0
1

3 个答案:

答案 0 :(得分:3)

在这种情况下,我会说这是未定义的行为。 bcconst对象,所有子对象(少mutable s) 1 也是如此,因此bc.v也应该是const无论如何,class const_iterator { public: const T& dereference() const; // complicated }; class iterator : public const_iterator { public: T& dereference() const { return const_cast<T&>(const_iterator::dereference()); } }; 对象是UB 2

[1] C ++ 03 3.9.3 / 3:

  

const限定类对象的每个非静态,非可变,非引用数据成员都是const-   合格...

[2] C ++ 03 7.1.5.1/4:

  

除了可以修改声明为mutable(7.1.1)的任何类成员之外,任何修改const的尝试都是如此   对象在其生命周期(3.8)中导致未定义的行为。

编辑响应问题的编辑:不,修改后的代码版本不会导致未定义的行为。这可能是不好的做法,但实际上有时可能很有用。你可以,例如。使用它通过const-iterators(DRY)实现类的迭代器:

iterator

当然,这取决于{{1}} s只能由可变容器构成,const和非const版本没有区别(没有COW等),但这是相当常见的

答案 1 :(得分:3)

在您的特定情况下,它是未定义的行为,因为对象 const,而不仅仅是引用。在以下情况下,它将是不良做法(危险地接近未定义行为):

void f( const BreakConst& b ) {
   bc.break_stuff();
}
int main() {
   BreakConst b;
   f( b );
}

不同之处在于,在这种情况下,实际对象不是const,即使f级别的引用是。危险地接近Undefined Behavior来自这样一个事实,即成员函数转换为const-ness不可能知道调用它的对象是否为const,因此你已经失去了所有控制。

答案 2 :(得分:2)

编辑后:

,这不是未定义的。您可以通过const引用修改可变对象;这是完全允许和合法的。


编辑之前:

是的,它必须是未定义的,因为标准(我正在看draft here)清楚地说:

  

§7.1.6.1.4

     

除了可以修改声明为mutable(第77.1.1节)的任何类成员之外,任何在其生命周期内修改const对象的尝试(第3.8节)都会导致未定义的行为。

所以是的 - 因为成员不可变,修改它显然是未定义的行为。

我不知道为什么规则是这样的,这是否是故意的,是否确实是一个漏洞,它是否也违反了另一条规则,你应该如何告诉我看着它等等......但关于它是否是UB的问题:是的,它根据标准未定义。