can memcpy() be used to change "const" member data?
对于具有
1 | struct point { const int x; const int y; }; |
用作成员数据
1 2 3 4 5 | struct Foo { point pt{ 0, 0 }; void move_x(int value); }; |
如何写
1 2 3 4 5 6 | #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_; } |
这可以使用指针安全地完成
1 2 3 4 5 6 7 8 9 10 11 12 | #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 }); } }; |
但是
请注意,客户根本不关心
1 2 3 4 5 | Foo foo; foo.move_x(314); // (314, 0) Bar bar; bar.move_x(3141); // (3141, 0) |
这显然是未定义的行为。现在,"可以"这样做吗?当然,它可以,但只是在编译器不会抱怨的意义上。但是 C 的一方面是因为编译器不抱怨它并不意味着生成的代码可以正常工作。
有人编写一些读取
一个现代的优化编译器会正确地假设,因为代码正在读取
然后,倒霉的程序员会花一周时间试图弄清楚为什么代码显然没有按照程序所说的那样做。
尝试将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #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("%d\ ", f.bar()); } |
以上结果
1 2 | error: invalid conversion from a€?const void*a€? to a€?void*a€? [-fpermissive] memcpy(&x, y, sizeof(int)); |
虽然我在此示例中使用了
,您会发现相同的结果
1 | const int *x; |
但是,如果您删除
1 | int x; |
(或
所以这引出了一个问题,如果你知道某些东西将被声明为
-
如果您有能力更改声明,您不能自己删除
const 吗? -
如果您无法更改声明,那么您是否有充分的理由试图打破
const 做出的"Promise"?