下面的代码是不良做法还是未定义的行为?本质上我调用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
答案 0 :(得分:3)
在这种情况下,我会说这是未定义的行为。 bc
是const
对象,所有子对象(少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的问题:是的,它根据标准未定义。