c – 通过在构造过程中获得的指针修改const对象

前端之家收集整理的这篇文章主要介绍了c – 通过在构造过程中获得的指针修改const对象前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我刚刚发现,在没有任何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中的情况下)也是未定义的行为,

解决方法

const强制执行“按位定常”,但是你通常想要的是“逻辑常量”.

在包含指针的对象的情况下,这意味着const成员函数不能修改指针本身,而是可以修改指针所指向的内容.

这已经很长时间了.

为了获得逻辑常数,您可以使用mutable(或有时const_cast)来允许修改不影响对象逻辑状态的成员(例如,缓存值/记忆),以及2)通常必须手动强制不写入数据通过一个指针(但是如果它是一个拥有的指针,那么所有权应该被委托给一个仅管理该数据的所有权的对象,在这种情况下使其成为const应该通常阻止写入其拥有的数据).

只要有一个非const指针指向可能本身已被修改的数据的具体细节,那么你基本上只是得到一个与常量常用的大致相同的东西:获取非const访问数据,否则你将只有一个const指针.这取决于您确保只使用不会导致问题的方式(但是只有通过该指针进行和/或写入本身并不会导致问题).

换句话说,我们这里有两个单独的指针,一些数据.这可以让您访问对象的数据.在一个const成员函数中,只能通过这个读取(不)写入数据,除非(如上所述)它被标记为可变的.在这种情况下,您将保存第二个指针到相同的数据.既然没有什么可以将它标记为一个指向const的指针,那就不是这样,所以你得到对它指向的数据的非const访问.

猜你在找的C&C++相关文章