c-可以使用位置“ new”来更改“ const”数据吗?
作者:互联网
[这是can memcpy() be used to change “const” member data?的后续措施.Idiomatic Way to declare C++ Immutable Classes确实引起了问题,尤其是this回答“在围绕不可变数据设计的语言中,它知道(尽管)(逻辑)不可变也可以“移动”数据”. ]
给定具有const成员的结构
struct point2d { const int x; const int y; }; // can't change to remove "const"
持有指向point2d的指针的类可以指向具有不同值的新point2d实例.
struct Bar
{
std::unique_ptr<point2d> pPt_{ new point2d{ 0, 0 } };
const point2d& pt() const {
return *pPt_;
}
void move_x(int value) {
pPt_.reset(new point2d{ pt().x + value, pt().y });
}
};
酒吧的客户看到:
Bar bar; // (0, 0)
bar.move_x(3141); // (3141, 0)
point2d和Bar都完全按照要求工作.是的,point2d是完全不变的.
但是,我真的很喜欢Bar的另一种实现,该实现将point2d实例存储为成员数据.有什么办法可以做到这一点?使用新的放置可能会导致undefined behavior(请参阅注释).
#include <new>
struct Baz
{
point2d pt{ 0, 0 };
void move_x(int value) {
// ** is this undefined behavior ? **
new (&pt) point2d { pt.x + value, pt.y };
}
};
不能直接使用point2d作为成员数据来解决(潜在的?)未定义行为吗?
struct Blarf
{
unsigned char pt_[sizeof(point2d)];
const point2d& pt() const {
return *reinterpret_cast<const point2d*>(pt_);
}
Blarf() {
new (&pt_) point2d{ 0, 0 };
}
void move_x(int value) {
new (&pt_) point2d{ pt().x + value, pt().y };
}
};
哪个是对的?只是布拉夫?还是巴兹还行吗?还是都不是,唯一的解决方案是Bar?
解决方法:
您可以在对象的生命周期结束后重新使用存储.生存期以析构函数调用结束.在技术上没有任何问题.
在对象的生命周期结束后使用该对象,就像在我编写此答案时所提供的示例代码所做的那样
pt.~point2d();
new (&pt) point2d { pt.x + value, pt.y };
是未定义的行为.
如果您坚持将点类与const字段一起使用,则可以这样解决:
void move_x( int const value )
{
auto const old_pt = pt;
pt.~point2d();
::new (&pt) point2d { old_pt.x + value, old_pt.y };
}
这可能感觉像是不必要的复杂性和可能的微观效率低下,但是,不必要的复杂性就是要点类.
标签:placement-new,c,const,immutability 来源: https://codeday.me/bug/20191009/1878367.html