memcpy() 可以用来更改"const"成员数据吗?
can memcpy() be used to change "const" member data?
对于具有const
成员的struct
struct point { const int x; const int y; };
用作成员数据
struct Foo
{
point pt{ 0, 0 };
void move_x(int value);
};
如何编写Foo::move_x()
来更新Foo::pt
? 可以使用memcpy()
吗?
#include <memory.h>
void Foo::move_x(int value)
{
const point pt_{ pt.x + value, pt.y };
(void) memcpy(&pt, &pt_, sizeof(pt_)); // pt = pt_;
}
这可以使用指针安全地完成
#include <memory>
struct Bar
{
std::unique_ptr<point> pPt_{ new point{ 0, 0 } };
const point& pt() const {
return *pPt_;
}
void move_x(int value) {
pPt_.reset(new point{ pt().x + value, pt().y });
}
};
但是point
总是存储在堆上而不是存储在Bar
中。
请注意,客户端根本不关心point
:
Foo foo;
foo.move_x(314); // (314, 0)
Bar bar;
bar.move_x(3141); // (3141, 0)
这显然是未定义的行为。现在,"可以"做到这一点吗?当然,它可以,但只是在编译器不会抱怨的意义上。但是C++的一个方面只是因为编译器不抱怨,并不意味着生成的代码可以正常工作。
有人编写一些读取pt
、调用move_x()
然后再次读取pt
的代码只是时间问题。
现代的优化编译器会正确地假设,因为代码正在读取const
实例,所以它们的值不能改变,然后继续优化从pt
的第二次读取,使用从 CPU 寄存器中第一次读取pt
缓存的数据。
然后,倒霉的程序员将花一周的时间试图弄清楚为什么代码显然没有做程序所说的应该做的事情。
尝试将memcpy
与const
成员一起使用时,您将收到编译器错误,如下所示:
#include <cstdlib>
#include <cstdio>
#include <cstring>
struct foo
{
public:
foo(int init_x);
const int x;
int bar();
};
foo::foo(int init_x): x(init_x) {}
int foo::bar()
{
int *y = (int *) malloc(sizeof(int));
*y = 6;
memcpy(&x, y, sizeof(int));
return x;
}
int main(int argc, char *argv[])
{
foo f{5};
printf("%dn", f.bar());
}
以上结果是
error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
memcpy(&x, y, sizeof(int));
虽然我在这个例子中使用了const int
,但如果你改用const int
指针成员,你会发现相同的结果,即
const int *x;
但是,如果删除const
描述符并使用:
int x;
(或int *x;
,就此而言)错误不再发生,并且程序打印6
,正如人们所期望的那样。
所以这就引出了一个问题,如果你知道某件事将被声明为const
:
- 如果你有能力改变声明,你不能自己删除
const
吗? - 如果你不能改变声明,你有充分的理由想要打破
const
做出的"承诺"吗?
相关文章:
- 不允许运算符 const 参数调用 const 成员函数
- c++ 是否保证标头初始化的静态 const 成员跨编译单元和库共享单个实例?
- 在类声明中初始化 const 成员变量时在调试模式下出现异常
- 如何避免将 const 和非 const 成员函数输入到模板中的代码重复
- 初始化 const 成员的正确方法
- 使用 Boost 对具有 const 成员的类进行序列化
- 非常量调用 const 成员函数失败,只读位置C++
- PIMPL类的设置应该是const成员函数
- 与其他静态const成员初始化静态常量成员
- decltype 不会推断 const 对象的 const 成员
- 如何初始化不是静态的const成员
- 如何使用常量变量初始化类的 const 成员变量
- 使用模板参数初始化静态 const 成员
- 与const成员配对的向量
- 通过参考const成员通过参考时,尝试引用已删除的函数
- const成员初始化之前的用法是GCC和Clang的这种预期行为
- 通过const成员变量访问内联函数
- 与const成员一起安排新的和班级的分配
- 在const函数中调用非CONST成员的非const函数
- 为什么即使对于 "copy on write" 的 const 成员函数也返回一个代理类?