[ 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." ]
Given a struct
with const
members
struct point2d { const int x; const int y; }; // can't change to remove "const"
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 });
}
};
Clients of Bar
see:
Bar bar; // (0, 0)
bar.move_x(3141); // (3141, 0)
Both point2d
and Bar
are working exactly as desired; yes, point2d
is completely immutable.
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 };
}
};
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 };
}
};
Which is correct? Just Blarf
? Or is Baz
also OK? Or neither, and the only solution is Bar
?