C++ Logo

std-proposals

Advanced search

Re: [std-proposals] [[packed]] std::unaligned

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Mon, 11 Dec 2023 20:55:17 -0500
On Mon, Dec 11, 2023 at 8:25 PM Frederick Virchanza Gotham via
Std-Proposals <std-proposals_at_[hidden]> wrote:

> On Mon, Dec 11, 2023 at 8:35 PM Arthur O'Dwyer wrote:
> >
> > Thanks :) but I don't think `is_trivially_relocatable` is useful here.
> You never relocate-out-of (nor into) a `T` here. And the requirements on
> `T` are much stricter than "trivially relocatable"; for example, you
> actually need it to be trivially destructible, or else `unaligned<T>` won't
> have any destructor.
> > For example: I don't think it makes sense to talk about
> `std::unaligned<std::string>`. I don't know what the semantics of that
> would be.
>
> You've done a lot more work on trivial relocatability than I have, but
> anyway let me try tease this out. [...]
> you said in your last post that I "never relocate-out-of (nor
> into) a `T`", but if you look at my implementation of the assignment
> operator (which I implemented as a template function), I do a memcpy
> to a suitably-aligned T-sized buffer and then perform an operation on
> it -- it is for this reason that I need T to be trivially relocatable.
>


Ah, I'd missed that part. You're right that T does need to be trivially
relocatable in order for them to work. *But...*

You also mentioned that it must have a trivial destructor but I think
> this matter is covered by Connor's use of:
>
> ~unaligned() requires std::is_trivially_destructible_v<T> =
> default;
> [...]
> So maybe this compiler error is good enough?
>

That last bit is exactly my point. The destructor *also* requires that T be
trivially destructible!
Any T that is trivially relocatable and trivially destructible is
necessarily also trivially move-constructible (by the same logic that tells
you that if x+0 = 0 then x=0).
So it's "necessary, but not sufficient" for T to be trivially relocatable.
Your `unaligned<T>` won't work for T=string, or T=unique_ptr<int>, or any
other type that is not trivially copyable. It is true that all such types
are also, necessarily, trivially relocatable. Every trivially copyable type
is trivially relocatable. But "trivially relocatable" itself is not
sufficient for what you're doing; what you need is "trivially copyable."

I also strongly suspect that your use of `__datasizeof` (which *is* in
Clang trunk, btw, so you don't need my fork for that part either) is more
trouble than it's worth. At the very least you'd want to write some tests
that exercise it. I suspect you'll find that some of those `bit_cast`s fail
to compile, and that changing `__datasizeof` to `sizeof` completely fixes
the problem.


Furthermore, I think that 'unaligned' should be compatible with
> 'optional' so that you can do the following:
>
> std::optional<SomeClass> monkey;
> monkey.emplace(1,2,3,56.7L);
> std::unaligned<SomeClass> donkey( std::take_ownership_t(), monkey );
>
> After these three lines of code, 'monkey' no longer has a value, and
> so the 'donkey' object is now responsible for destroying the SomeClass
> object


In my libc++ fork and on my blog
<https://quuxplusone.github.io/blog/2023/03/01/priority-queue-displace-top/>
(but not in P1144), I use the verb "displace" for this; as in
    template<class T> T optional<T>::displace() { has_value_ = false;
return std::relocate(&value_); }
and
    std::unaligned<SomeClass> donkey = monkey.displace();

–Arthur

Received on 2023-12-12 01:55:31