Date: Tue, 28 Oct 2025 14:01:33 +0000
On Tue, 28 Oct 2025, 12:48 Nikl Kelbon, <kelbonage_at_[hidden]> wrote:
> > Again, this is potentially undefined behaviour.
>
> Thats why it must be in standard library, others cannot do it without UB
>
> About memcpy, it seems for you, that its not correct, because you're used
> to the fact that it's wrong. But if you memswap ANY type twice into buffer
> and into original place again any type, even self reference, will work.
>
The standard is clear. If you do that for a type which is not trivially
copyable, it's undefined.
> Its impossible to break something with such memory manipulations
>
Wanna bet?
Consider:
std::variant<A,B> v1{A{}};
std::variant<A,B> v2{B{}};
try {
v1 = std::move(v2);
} catch (...) {
// Assume v1 cannot be valueless
std::get<A>(v1).fun();
}
and a global:
std::map<void*, std::type_info> objects;
where B::B(B&&) does:
B::B(B&& b)
try {
objects[this] = typeid(B);
} catch (...) {
objects.erase(this);
}
And:
void A::fun()
{
assert(objects[this] == typeid(A));
}
The move ctor of B throws, so if you had memcpy'd the A aside and then
swapped it back again, objects would not contain any element for the
address of that object. When you call A::fun() it finds the object is not
"live".
This is just a demonstration of one way that non-trivially copyable objects
can break if you memcpy them out and back again. It's not impossible.
> > Again, this is potentially undefined behaviour.
>
> Thats why it must be in standard library, others cannot do it without UB
>
> About memcpy, it seems for you, that its not correct, because you're used
> to the fact that it's wrong. But if you memswap ANY type twice into buffer
> and into original place again any type, even self reference, will work.
>
The standard is clear. If you do that for a type which is not trivially
copyable, it's undefined.
> Its impossible to break something with such memory manipulations
>
Wanna bet?
Consider:
std::variant<A,B> v1{A{}};
std::variant<A,B> v2{B{}};
try {
v1 = std::move(v2);
} catch (...) {
// Assume v1 cannot be valueless
std::get<A>(v1).fun();
}
and a global:
std::map<void*, std::type_info> objects;
where B::B(B&&) does:
B::B(B&& b)
try {
objects[this] = typeid(B);
} catch (...) {
objects.erase(this);
}
And:
void A::fun()
{
assert(objects[this] == typeid(A));
}
The move ctor of B throws, so if you had memcpy'd the A aside and then
swapped it back again, objects would not contain any element for the
address of that object. When you call A::fun() it finds the object is not
"live".
This is just a demonstration of one way that non-trivially copyable objects
can break if you memcpy them out and back again. It's not impossible.
Received on 2025-10-28 14:01:50
