C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Relocation in C++

From: Sébastien Bini <sebastien.bini_at_[hidden]>
Date: Thu, 22 Sep 2022 19:47:52 +0200
On Wed, Sep 21, 2022 at 4:51 PM Edward Catmur <ecatmur_at_[hidden]>
wrote:

> std::decompose would need to be magic (compiler-implemented), to be able
> to call destructors on nonrelocated subobjects, so it would be able to
> bypass access checks anyway; it might be possible to implement it in the
> language with reflection once that arrives, but it's widely expected that
> reflection will also allow bypassing access checks.
>
> So the danger is actually that std::decompose would be too powerful and
> allow arbitrary code to access private/protected base subobjects of
> unrelated class types; but this can be prevented by requiring the compiler
> to look at the context of the call to determine whether the caller is
> allowed to access that base class subobject.
>

I fail to see the real danger here. Sure we may extract private/protected
subobjects, but the source object we extracted them from is destroyed. So
it's not like we can mess with it. We simply get independant objects that
have no relationship with one another, which is guaranteed by the fact that
the object we extracted them from has no user-provided constructors and
destructor.


> > If `operator T()` were prvalue qualified that would help prevent bugs,
>> using deducing this on the object parameter:
>> >
>> > T relocating_wrapper<T>::operator T(this relocating_wrapper self)
>> { return self.opt_.pop(); }
>> >
>> > Users would have to go to considerable lengths to misuse it and the
>> resulting code would have a manifest use-after-move bug. Yes, there's still
>> a double relocation but that should be elidable.
>>
>> That code is already okay w/t C++23 right?
>>
>
> Absolutely, that's perfectly legal C++23.
>

One less thing to worry about :) Thanks for confirming.


> That would also open the door to the non-variadic syntax:
>> vector<T>::push_back(decltype(auto) x).
>>
>
> No, because currently `push_back` isn't a template but a lvalue-xvalue
> overload set. It would be beneficial to add prvalue to that overload set: vector<T>::push_back(T
> value), given that overload resolution between lvalue/xvalue/prvalue is
> established as unambiguous.
>

Sorry, I meant to use decltype(auto) with no parameter packs. More like:

void vector<T>::push_back_impl(decltype(auto) val);
void vector<T>::push_back(T const& val) { push_back_impl(reloc val); }
void vector<T>::push_back(T&& val) { push_back_impl(reloc val); }
void vector<T>::push_back(T val) { push_back_impl(reloc val); }


> Every operator token is currently a keyword; there are four identifiers
> with special meaning (final, override, import and module) but they are not
> operators.
>
> The problem with having it as an operator that is not a keyword is
> parsing; is `reloc x;` a discarded-value relocation expression (destroying
> x) or is it the declaration of a variable `x` with type `reloc`? If `reloc`
> is not allowed as an identifier, then that's basically the same as making
> it a keyword.
>

Fair point. When I first thought of this reloc operator, I considered using
a new symbol instead. Like `$x`, `_at_x`, or `>x`, etc... instead of `reloc
x`. However I do find `reloc` to be better than a symbol: first, it clearly
conveys the intent. Second, it is visually more eye-catching, which helps
when reading code. I reckon it's important to quickly see where relocation
happens as it ends the scope of variables.

FWIW, C has historically handled this by introducing new keywords with
> _Reserved names and requiring code to opt-in to friendlier names by
> #including a header that implicitly #defines the new keyword to the
> _Reserved name. But that's not been workable in C++ since so much of our
> code is in headers and so it would leak into code that includes those
> headers. Perhaps modules would make it possible to opt-into a new keyword.
>

I figured a simple #if __cplusplus >= 202900L would do the job?

Received on 2022-09-22 17:48:05