可以放置“新"用于改变"const"标记.数据? [英] can placement "new" be used to alter "const" data?
问题描述
[这是对 can memcpy( )用于更改"const"成员数据?.而宣告C ++不可变类的惯用方式确实引起了问题,尤其是此回答在围绕不可变数据设计的语言中,尽管它具有(逻辑上)的不变性." ]
[ This is a follow-up to can memcpy() be used to change "const" member data?. And Idiomatic Way to declare C++ Immutable Classes really gets at the issue, especially this answer "In a language designed around immutable data, it would know it can "move" your data despite its (logical) immutability." ]
给struct
和const
个成员
struct point2d { const int x; const int y; }; // can't change to remove "const"
持有指向point2d
的指针的类可以指向具有不同值的新point2d
实例.
A class which holds a pointer to point2d
can point to a new point2d
instance with different values.
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 bar; // (0, 0)
bar.move_x(3141); // (3141, 0)
point2d
和Bar
均按要求工作.是的,point2d
是完全不变的.
Both point2d
and Bar
are working exactly as desired; yes, point2d
is completely immutable.
但是,我真的很希望Bar
的另一种实现将point2d
实例存储为成员数据.有什么办法可以做到这一点?使用放置new
可能会导致未定义的行为(请参见注释).
However, I'd really like a different implementation of Bar
that stores the point2d
instance as member data. Is there any way to achieve this? Using placement new
supposedly results in undefined behavior (see comment).
#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
作为成员数据是否可以解决(潜在的?)未定义行为?
Does not using point2d
directly as member data work-around the (potential?) undefined behavior?
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 };
}
};
哪个是正确的?只是Blarf
?还是Baz
还可以吗?还是都不是,唯一的解决方案是Bar
?
Which is correct? Just Blarf
? Or is Baz
also OK? Or neither, and the only solution is Bar
?
推荐答案
在对象的生命周期结束后,您可以重用存储.生存期以析构函数调用结束.在技术上没有任何问题.
You can reuse the storage after the lifetime of the object has ended. The lifetime ends with the destructor call. There's nothing technically problematic in that.
使用对象在其生命周期结束后,如所示示例代码我在
Using the object after its lifetime has ended, as the presented example code did at the time I wrote this answer in
pt.~point2d();
new (&pt) point2d { pt.x + value, pt.y };
是未定义的行为.
如果您坚持将点类与const
字段一起使用,则可以这样解决:
If you insist on using the point class with const
fields, you can work around that like this:
void move_x( int const value )
{
auto const old_pt = pt;
pt.~point2d();
::new (&pt) point2d { old_pt.x + value, old_pt.y };
}
这可能感觉像是不必要的复杂性和可能的微观效率低下,但不必要的复杂性是点类.
That may feel like unnecessary complication and possible micro-inefficiency, but rather, the unnecessary complication is the point class.
这篇关于可以放置“新"用于改变"const"标记.数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!