#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中的情况下)也是未定义的行为,
解决方法
在包含指针的对象的情况下,这意味着const成员函数不能修改指针本身,而是可以修改指针所指向的内容.
这已经很长时间了.
为了获得逻辑常数,您可以使用mutable(或有时const_cast)来允许修改不影响对象逻辑状态的成员(例如,缓存值/记忆),以及2)通常必须手动强制不写入数据通过一个指针(但是如果它是一个拥有的指针,那么所有权应该被委托给一个仅管理该数据的所有权的对象,在这种情况下使其成为const应该通常阻止写入其拥有的数据).
只要有一个非const指针指向可能本身已被修改的数据的具体细节,那么你基本上只是得到一个与常量常用的大致相同的东西:获取非const访问数据,否则你将只有一个const指针.这取决于您确保只使用不会导致问题的方式(但是只有通过该指针进行和/或写入本身并不会导致问题).
换句话说,我们这里有两个单独的指针,一些数据.这可以让您访问对象的数据.在一个const成员函数中,只能通过这个读取(不)写入数据,除非(如上所述)它被标记为可变的.在这种情况下,您将保存第二个指针到相同的数据.既然没有什么可以将它标记为一个指向const的指针,那就不是这样,所以你得到对它指向的数据的非const访问.