【发布时间】:2016-10-27 20:56:27
【问题描述】:
我刚刚发现在没有任何const_cast 魔法的情况下修改 const 对象是多么容易。考虑:
#include <iostream>
class Test {
public:
Test(int v)
:m_val{ v },
m_ptr{ &m_val }
{}
int get() const { return m_val; }
void set(int v) const { *m_ptr = v; }
private:
int m_val;
int* m_ptr;
};
int main()
{
const Test t{ 10 };
std::cout << t.get() << '\n';
t.set(0);
std::cout << t.get() << '\n';
return 0;
}
Clang、GCC 和 MSVC 的最新版本不显示任何警告并产生预期的输出:
10 0
这是根据当前标准明确定义的行为吗?如果它是未定义的,如果 m_val 是 std::aligned_storage_t<sizeof(int), alignof(int)> 类型和构造函数 new'ed int 呢?我相信在小缓冲区优化方面这是很常见的情况。
编辑
谢谢,看来这只是另一种自爆的方式。 令人不安的是:
struct Test2 {
int i;
void operator()() { ++i; }
};
const std::function<void()> f{ Test2{ 10 } };
f();
当实现选择将Test2 对象存储在f 中时也是未定义的行为(在libc++ 和Visual Studio 中就是这种情况)
【问题讨论】:
-
我认为是UB修改了
m_val。 -
"7.1.5.1/4:除了可以修改任何声明为可变的类成员(7.1.1)外,任何在其生命周期(3.8)期间修改 const 对象的尝试都会导致未定义行为。”
-
对于
constexpr,编译器发现了错误:Demo。 :-)