Straw polls for P1144R0 "Object relocation in terms of move plus destroy"

396 views
Skip to first unread message

Arthur O'Dwyer

unread,
Nov 11, 2018, 8:35:40 PM11/11/18
to ISO C++ Standard - Future Proposals
P1144R0 "Object relocation in terms of move plus destroy" was presented to SG17 (EWGI) in San Diego. (Thanks to Corentin Jabot for trying to make it happen!) The paper lists the following straw polls that could have been taken. None of these polls were taken, and no feedback was given on the paper in San Diego.

So I'd like to get your opinions!  Please reply in this thread with your !votes on any or all of the following statements, in the traditional WG21 straw poll format: "Strongly For" the statement as written; "For" it; "Neutral" (as in, you considered the question and your expert opinion is that you are neutral on it — please do not use this option as a synonym for abstaining due to lack of an opinion); "Against" the statement as written; or "Strongly Against" it.

The polls will remain open for one week, until Sunday 2018-11-18. If you don't want your !votes to be public, you can always email them to me privately.
I will tally the ballots and report the results in P1144R1, which will appear in the post-San-Diego mailing (submission deadline: 2018-11-26).

Here are the polls. Please vote in any or all of them, but only after reading the paper. When a poll says "...as proposed in this paper," it's referring to the formal wording from P1144R0. You would have to read that formal wording to know what's being asked!
---------------------------------------

EWG1. We approve of the general idea that user-defined classes should be able to warrant their own trivial relocatability via a standard mechanism.

EWG2. We approve of the general idea that user-defined classes which follow the Rule of Zero should inherit the trivial relocatability of their bases and members.

EWG3. Nobody should be able to warrant the trivial relocatability of class `C` except for class `C` itself (i.e., we do not want to see a customization point analogous to `std::hash`).

EWG4. A class should be able to warrant its own trivial relocatability via the attribute `[[trivially_relocatable]]`, as proposed in this paper.

EWG5. A class should be able to warrant its own trivial relocatability via some attribute, but not necessarily under that exact name.

EWG6. A class should be able to warrant its own trivial relocatability as proposed in this paper, but we prefer to see a contextual keyword rather than an attribute.

EWG7. If a trait with the semantics of `is_trivially_relocatable<T>` is added to the `<type_traits>` header, the programmer should be permitted to specialize it for program-defined types (i.e., we want to see that trait itself become a customization point analogous to `std::hash`).

EWG8. Trivial relocatability should be assumed by default. Classes such as those in Appendix C should indicate their non-trivial relocatability via an opt-in mechanism.

EWG9. To simplify conditionally trivial relocation, if an attribute with the semantics of `[[trivially_relocatable]]` is added, it should take a boolean argument.

LEWG10. The algorithm `uninitialized_relocate(first, last, d_first)` should be added to the `<memory>` header, as proposed in this paper.

LEWG11. The type trait `is_relocatable<T>` should be added to the `<type_traits>` header, as proposed in this paper.

LEWG12. If `is_relocatable<T>` is added, then we should also add `is_nothrow_relocatable<T>`, as proposed in this paper.

LEWG13. The type trait `is_trivially_relocatable<T>` should be added to the `<type_traits>` header, under that exact name, as proposed in this paper.

LEWG14. We approve of a trait with the semantics of `is_trivially_relocatable<T>`, but possibly under a different name. (For example, `is_bitwise_relocatable`.)

LEWG15. If `is_trivially_relocatable<T>` is added, under that exact name, then the type trait `is_trivially_swappable<T>` should also be added to the `<type_traits>` header.

-----------------------

Discussion and comments on P1144R0 is also welcome — preferably in the original discussion thread, or via private email, but if it winds up in this thread, I'm okay with that.

Thanks,
Arthur

mihailn...@gmail.com

unread,
Nov 12, 2018, 5:05:44 AM11/12/18
to ISO C++ Standard - Future Proposals
I will take the liberty to express my thoughts in which my votes will become clear

I like the general direction. Initially I hoped triviality can be expressed in terms of functions and side effects, but it can't, it must be part of the type.

So, pro to all questions on the general direction.

I am also pro the library facilities.


Now, on the things that bother me.

First, traits will be superseded by Refection. I feel the traits API will have to be "rebased" which makes it much less attractive.

Second, and my main gripe - the use of attribute to create a new type (FWIW). 
This does not feel right and never will. Sure, creating a new type is pretty much unavoidable if we want all the benefits, but doing it this way is a hack. 

Can we do this in another, more type-systemy way? 
Can we have a magic base class? Can we have magic typedef. 
Can we make type specialization work (the folly way without the downsides)?

If we absolutely can not get away from the attribute joker, then can we create special attribute subtype that makes it clear it is special 
something like (off the top of my head) [[typedef: relocatable]], something to donate type-introducing attributes. 

Or of course, a keyword is probably best option - keywords are already used to both create and influence types (const, volatile, final etc). 

floria...@gmail.com

unread,
Nov 12, 2018, 11:54:23 AM11/12/18
to ISO C++ Standard - Future Proposals


Le lundi 12 novembre 2018 02:35:40 UTC+1, Arthur O'Dwyer a écrit :
P1144R0 "Object relocation in terms of move plus destroy" was presented to SG17 (EWGI) in San Diego. (Thanks to Corentin Jabot for trying to make it happen!) The paper lists the following straw polls that could have been taken. None of these polls were taken, and no feedback was given on the paper in San Diego.

So I'd like to get your opinions!  Please reply in this thread with your !votes on any or all of the following statements, in the traditional WG21 straw poll format: "Strongly For" the statement as written; "For" it; "Neutral" (as in, you considered the question and your expert opinion is that you are neutral on it — please do not use this option as a synonym for abstaining due to lack of an opinion); "Against" the statement as written; or "Strongly Against" it.

The polls will remain open for one week, until Sunday 2018-11-18. If you don't want your !votes to be public, you can always email them to me privately.
I will tally the ballots and report the results in P1144R1, which will appear in the post-San-Diego mailing (submission deadline: 2018-11-26).

Here are the polls. Please vote in any or all of them, but only after reading the paper. When a poll says "...as proposed in this paper," it's referring to the formal wording from P1144R0. You would have to read that formal wording to know what's being asked!
---------------------------------------

EWG1. We approve of the general idea that user-defined classes should be able to warrant their own trivial relocatability via a standard mechanism.
Strongly For

EWG2. We approve of the general idea that user-defined classes which follow the Rule of Zero should inherit the trivial relocatability of their bases and members.
Strongly For

EWG3. Nobody should be able to warrant the trivial relocatability of class `C` except for class `C` itself (i.e., we do not want to see a customization point analogous to `std::hash`).
For

EWG4. A class should be able to warrant its own trivial relocatability via the attribute `[[trivially_relocatable]]`, as proposed in this paper.
Neutral

EWG5. A class should be able to warrant its own trivial relocatability via some attribute, but not necessarily under that exact name.
Neutral

EWG6. A class should be able to warrant its own trivial relocatability as proposed in this paper, but we prefer to see a contextual keyword rather than an attribute.
Neutral

EWG7. If a trait with the semantics of `is_trivially_relocatable<T>` is added to the `<type_traits>` header, the programmer should be permitted to specialize it for program-defined types (i.e., we want to see that trait itself become a customization point analogous to `std::hash`).
Strongly Against

EWG8. Trivial relocatability should be assumed by default. Classes such as those in Appendix C should indicate their non-trivial relocatability via an opt-in mechanism.
Against

EWG9. To simplify conditionally trivial relocation, if an attribute with the semantics of `[[trivially_relocatable]]` is added, it should take a boolean argument.
Neutral

LEWG10. The algorithm `uninitialized_relocate(first, last, d_first)` should be added to the `<memory>` header, as proposed in this paper.
For

LEWG11. The type trait `is_relocatable<T>` should be added to the `<type_traits>` header, as proposed in this paper.
Strongly Against

LEWG12. If `is_relocatable<T>` is added, then we should also add `is_nothrow_relocatable<T>`, as proposed in this paper.
For

LEWG13. The type trait `is_trivially_relocatable<T>` should be added to the `<type_traits>` header, under that exact name, as proposed in this paper.
For

LEWG14. We approve of a trait with the semantics of `is_trivially_relocatable<T>`, but possibly under a different name. (For example, `is_bitwise_relocatable`.)
Strongly For

LEWG15. If `is_trivially_relocatable<T>` is added, under that exact name, then the type trait `is_trivially_swappable<T>` should also be added to the `<type_traits>` header.
For

Balog Pal

unread,
Nov 13, 2018, 4:09:53 AM11/13/18
to ISO C++ Standard - Future Proposals, floria...@gmail.com
>EWG2. We approve of the general idea that user-defined classes which follow the Rule of Zero should inherit the trivial relocatability of their bases and members.
>Strongly For

I don't see how that makes sense. R0 is based on user-declared spec functions. Can I do this to break relocability?

struct A {
A* p = this;
A** pp = &p;
};

floria...@gmail.com

unread,
Nov 13, 2018, 4:25:02 AM11/13/18
to ISO C++ Standard - Future Proposals
Your class A cannot keep its invariants (p points to this, and pp points to p) across copy or move. So it's fine in that case to also break on relocation.
For your class to be correct, you would need to write/disable copy and move constructors. In that case, rule of zero would not apply and relocability would not be inherited.

As defined in this proposal, relocability cannot break a class by default.

Balog Pal

unread,
Nov 13, 2018, 7:03:48 AM11/13/18
to std-pr...@isocpp.org
On 11/13/2018 10:25 AM, floria...@gmail.com wrote:
> Your class A cannot keep its invariants (p points to this, and pp points
> to p) across copy or move. So it's fine in that case to also break on
> relocation.
> For your class to be correct, you would need to write/disable copy and
> move constructors. In that case, rule of zero would not apply and
> relocability would not be inherited.

Right, that is not the good example. I still have a strong feeling that
R0 connects badly to this feature. The other direction looks more
obvious: just the presense of dtor looks completely irrelevant. Majority
of ctors handle different kinds of invariants.

I think I could construct one with virtual inheritance that uses no
user-defined ctors but has an embedded pointer.

As a general note this paper looks intimidatingly overcomplicated. As a
programmer I'd welcome a SIMPLE facility, where I can opt in for
relocability, and the library accounts for that. no composition, no
automatics, no heuristics, UB if I lied -- and the whole paper would fit
on a single page with a poll just to bikeshed the syntax for opt-in.

And the advanced logic can be added later on as real life experience is
gained how people use it. Perfect is enemy of good.


Arthur O'Dwyer

unread,
Nov 13, 2018, 10:50:20 AM11/13/18
to std-pr...@isocpp.org
On Tue, Nov 13, 2018 at 7:03 AM Balog Pal <pa...@lib.hu> wrote:
On 11/13/2018 10:25 AM, floria...@gmail.com wrote:
> Your class A cannot keep its invariants (p points to this, and pp points
> to p) across copy or move. So it's fine in that case to also break on
> relocation.
> For your class to be correct, you would need to write/disable copy and
> move constructors. In that case, rule of zero would not apply and
> relocability would not be inherited.

Right, that is not the good example. I still have a strong feeling that
R0 connects badly to this feature.  The other direction looks more
obvious: just the presense of dtor looks completely irrelevant. Majority
of ctors handle different kinds of invariants.

The behavior of the destructor is important. For example, in a class that owns a resource, the destructor is what frees that resource.
What distinguishes "relocate" from "move" is that "relocate" consists of "move plus destroy (of the source object)": If we don't consider the behavior of the destructor, then we're not considering the one thing that makes "trivially relocatable" different from "trivially move-constructible."
Specifically, if a user-defined dtor did not disable trivial relocatability, then `struct CountDestructions { std::string s; ~CountDestructions(); };` would be considered trivially relocatable, when it clearly is not. (That is: its relocation operation involves running user-provided mystery code that may have observable side effects.)

I think I could construct one with virtual inheritance that uses no
user-defined ctors but has an embedded pointer.

I would pay to see an example of a class that is_trivially_relocatable by P1144R0's definition without being actually trivially relocatable. If you can break P1144, please tell me.
I am not quite confident that my Godbolt implementation is bug-free, but hey, if you can find an example that breaks on Godbolt, I'll pay up, too.


As a general note this paper looks intimidatingly overcomplicated.

This sounds like a problem; I'd like to fix it. Can you send me an email off-thread naming the aspects of the paper that are "too complicated"?
The only thing I know to do about it so far, for R1, is that now that R0 has been put into a mailing, it would be acceptable to cut some of the material and replace it with notes saying "see R0" (for non-normative, digressive parts such as Section 5 and Appendix B).

 
As a
programmer I'd welcome a SIMPLE facility, where I can opt in for
relocability, and the library accounts for that. no composition, no
automatics, no heuristics, UB if I lied -- and the whole paper would fit
on a single page with a poll just to bikeshed the syntax for opt-in.

That wouldn't handle lambdas or primitive struct types such as `struct Person { std::string name; int age; }`.  I guarantee you that you wouldn't actually be happy with manual annotation. (The paper already alludes to the perils of manual annotation.)

–Arthur

Balog Pal

unread,
Nov 13, 2018, 12:47:33 PM11/13/18
to std-pr...@isocpp.org
A had the feeling like we are in two completely different
conversations... and that was the case indeed, I located the source.

All along I was talking about trivially relocatable (without pointing it
out, my bad). While the answers were provided in the general relocability.

This may provide some of the explanation of my previous claim on the
"overcomplicated". I just don't see any value from all those other
flavors. Neither from the top of my head nor from the paper. It provides
a good case for the trivial that I agree with and would like in the
language very much. As most of the types I work with are actually such.
And I do move them around in all kinds of operations not limited to
vector::push_back and sort.

What is the benefit of the other stuff? What cares for knowing a type is
nontrivially_throwing relocatable or nontrivially_nothrow_relocatable? I
mean as a separate, named concept, beyond its raw ingredients?

If you know that, and believe it is significant benefit, you need to
emphasize that in the paper bigtime (while benefits of just doing a bulk
big memcpy instead of formal constructions and destructions are IMO
evident.)

Also providing a safe set of rules that can figure out
trivial_relocation for an aggregate/composite should be easier. Both to
compose and evaluate that is quite important estimating chances to get
into the standard and at all and the overall time it would take.

Even at being at the start of the C++23 timeframe it is a factor worth
considering. Also if you feel strongly about the more general approach,
it can be added in a next paper after this is accepted.

Matthew Woehlke

unread,
Nov 13, 2018, 12:48:59 PM11/13/18
to Arthur O'Dwyer, std-pr...@isocpp.org
On 11/11/2018 20.35, Arthur O'Dwyer wrote:
> EWG1. We approve of the general idea that user-defined classes should be
> able to warrant their own trivial relocatability via a standard mechanism.

SF.

> EWG2. We approve of the general idea that user-defined classes which follow
> the Rule of Zero
> <https://web.archive.org/web/20130607234833/http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html>
> should inherit the trivial relocatability of their bases and members.

F.

> EWG3. Nobody should be able to warrant the trivial relocatability of class
> `C` except for class `C` itself (i.e., we do not want to see a
> customization point analogous to `std::hash`).

N leaning to A.

While this makes sense *in principle*, in practice it's not unusual to
want/need this optimization for a class which is outside of your control.

> EWG4. A class should be able to warrant its own trivial relocatability via
> the attribute `[[trivially_relocatable]]`, as proposed in this paper.

N leaning to A.

One of the reasons we tend to talk about "destructive move" is that
there are lifetime implications. It's not clear that this can be
correctly expressed via an attribute. It seems like users would need to
call a special flavor of dtor.

(I'm also far from convinced this is an "acceptable" use of an attribute.)

> EWG5. A class should be able to warrant its own trivial relocatability via
> some attribute, but not necessarily under that exact name.

N leaning to A.

This is an overly leading question; it assumes that "an attribute" is
the correct way to express trivial relocatability.

> EWG6. A class should be able to warrant its own trivial relocatability as
> proposed in this paper, but we prefer to see a contextual keyword rather
> than an attribute.

Strongly N.

Again, this is too leading. The correct solution might be:

class Foo
{
Foo(Foo~ other) = default; // relocating ctor
...
};

...which isn't really "a contextual keyword".

> EWG7. If a trait with the semantics of `is_trivially_relocatable<T>` is
> added to the `<type_traits>` header, the programmer should be permitted to
> specialize it for program-defined types (i.e., we want to see that trait
> itself become a customization point analogous to `std::hash`).

Weakly F.

This seems redundant with EWG3.

> EWG8. Trivial relocatability should be assumed by default. Classes such as
> those in Appendix C
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1144r0.html#non-trivial-samples>
> should indicate their non-trivial relocatability via an opt-in mechanism.

If you *literally* meant "all" classes, vs. e.g. those that meet some
reasonable criteria, then SA leaning toward OMDB.

> EWG9. To simplify conditionally trivial relocation
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1144r0.html#sample-conditional>,
> if an attribute with the semantics of `[[trivially_relocatable]]` is added,
> it should take a boolean argument.

I'm not even going to answer this one. As others, *way* too leading as
far as assuming a particular approach which does *not* have consensus.

> LEWG10. The algorithm `uninitialized_relocate(first, last, d_first)` should
> be added to the `<memory>` header, as proposed in this paper.

Weakly F.

> LEWG11. The type trait `is_relocatable<T>` should be added to the
> `<type_traits>` header, as proposed in this paper.

N.

> LEWG12. If `is_relocatable<T>` is added, then we should also add
> `is_nothrow_relocatable<T>`, as proposed in this paper.

N.

> LEWG13. The type trait `is_trivially_relocatable<T>` should be added to the
> `<type_traits>` header, under that exact name, as proposed in this paper.

F.

In practice, I'm not sure how useful the other two will be.

> LEWG14. We approve of a trait with the semantics of
> `is_trivially_relocatable<T>`, but possibly under a different name. (For
> example, `is_bitwise_relocatable`.)

F, I guess.

Seems a bit redundant with LEWG13, but I guess the point is for people
that want to complain about the color of the bikeshed.

> LEWG15. If `is_trivially_relocatable<T>` is added, under that exact name,
> then the type trait `is_trivially_swappable<T>` should also be added to the
> `<type_traits>` header.

N.

--
Matthew

mihailn...@gmail.com

unread,
Nov 13, 2018, 2:24:10 PM11/13/18
to ISO C++ Standard - Future Proposals, arthur....@gmail.com
Matthew, the paper is not about "destructive move". 
In a way the paper is "what can do after dmove has failed" and "let's standardize established practices".

mihailn...@gmail.com

unread,
Nov 13, 2018, 3:23:49 PM11/13/18
to ISO C++ Standard - Future Proposals


On Tuesday, November 13, 2018 at 7:47:33 PM UTC+2, Balog Pal wrote:
A had the feeling like we are in two completely different
conversations... and that was the case indeed, I located the source.

All along I was talking about trivially relocatable (without pointing it
out, my bad). While the answers were provided in the general relocability.

This may provide some of the explanation of my previous claim on the
"overcomplicated". I just don't see any value from all those other
flavors. Neither from the top of my head nor from the paper. It provides
a good case for the trivial that I agree with and would like in the
language very much.  As most of the types I work with are actually such.
And I do move them around in all kinds of operations not limited to
vector::push_back and sort.

What is the benefit of the other stuff? What cares for knowing a type is
nontrivially_throwing relocatable or nontrivially_nothrow_relocatable? I
mean as a separate, named concept, beyond its raw ingredients?

Mildly agree.

I wonder could we just drop trivially and go with relocatable only to mean a trivial one and have no non-trivial relocatable concept on its own

Arthur O'Dwyer

unread,
Nov 13, 2018, 4:20:11 PM11/13/18
to std-pr...@isocpp.org
On Tue, Nov 13, 2018 at 3:23 PM <mihailn...@gmail.com> wrote:
On Tuesday, November 13, 2018 at 7:47:33 PM UTC+2, Balog Pal wrote:
A had the feeling like we are in two completely different
conversations... and that was the case indeed, I located the source.

All along I was talking about trivially relocatable (without pointing it
out, my bad). While the answers were provided in the general relocability.

This may provide some of the explanation of my previous claim on the
"overcomplicated". I just don't see any value from all those other
flavors. Neither from the top of my head nor from the paper. It provides
a good case for the trivial that I agree with and would like in the
language very much.  As most of the types I work with are actually such.
And I do move them around in all kinds of operations not limited to
vector::push_back and sort.

What is the benefit of the other stuff?

My thinking was that it is useful to give a proper name to the "relocate" operation — the verb itself — separately from the question of whether the operation is trivial or not. Compare "destructible" versus "trivially destructible"; I believe the case is exactly analogous.  Personally, I would strongly object to a proposal that was "P1144R0, but with is_trivially_relocatable_v renamed to just is_relocatable_v."  (However, I've seen other informal proposals, such as I think Florian's, where "relocate" was being introduced as a whole new verb with a completely different meaning, and in which the operation was a black box with no finer-grained adverb structure. E.g. in Pablo's N4158 "Destructive Move," there was no way to ask whether the operation was "trivial."

So P1144R0 provides the "whole relocatability package" — everything the programmer could need in order to work with relocatability. This means the uninitialized-memory algorithm and the trio of type traits. You can do the operation; you can ask if you can do the operation; and you can ask whether the operation is nothrow or trivial, just like with "constructible" and "destructible" and "swappable" and so on.

What cares for knowing a type is
nontrivially_throwing relocatable or nontrivially_nothrow_relocatable? I
mean as a separate, named concept, beyond its raw ingredients?

It is at least possible for the user-programmer to build `is_nothrow_relocatable` and `is_relocatable` by himself, using the existing building blocks `is_nothrow_{con,de}structible` and `is_{con,de}structible`. So we technically don't need those type traits.

`is_nothrow_relocatable` is useful for `vector::resize`. To do resize at all, our `T` must be relocatable. We'll do a loop move-constructing, and then a second loop destructing. But if our `T` is nothrow relocatable, then we can do a single loop relocating (that is, move-constructing and destructing, element by element); this will be cache-friendlier. But if our `T` is trivially relocatable, then we don't need any loop, and we just do a single memcpy.

(Here please ignore the stupid party tricks `std::vector` does with move_if_noexcept on copyable types. Let's either assume all our types are move-only, or assume we wrote our own sane `vector` class.)

I admit I am worried about the meaning of `is_nothrow_relocatable`. Suppose I have

    struct [[trivially_relocatable]] Cat {
        Cat(Cat&&) noexcept(false);  // might throw
        ~Cat();
    };

This `Cat` is relocatable, and it is trivially relocatable. Is it "nothrow relocatable"?  If we build `is_nothrow_relocatable` ourselves out of `is_nothrow_move_constructible` and `is_nothrow_destructible`, then we'll say `Cat` is NOT nothrow relocatable. And in fact it would be dangerous for vector::resize to use a single loop instead of a double loop. But if vector::resize uses `memcpy` — which it is permitted to do, in `Cat`'s case — then the whole operation will definitely be nothrow in practice.
I think the only sane solution is to say that `Cat` is NOT nothrow relocatable, even though it is trivially relocatable.

One way out of the dilemma would be to eliminate is_nothrow_relocatable (and is_relocatable) from the proposal.  But I think it doesn't make any sense to eliminate any single piece out of the jigsaw puzzle, if that elimination would leave a very obvious puzzle-piece-shaped hole that any user-programmer could just fill back in.  If we leave holes, we should make sure they are not puzzle-piece-shaped. :P

If you know that, and believe it is significant benefit, you need to
emphasize that in the paper bigtime (while benefits of just doing a bulk
big memcpy instead of formal constructions and destructions are IMO
evident.)

The benefit of is_nothrow_relocatable is much much smaller, but I think it's there.
In fact, that's pretty much the only benefit that Pablo's N4158 was going to get, and it was well-received enough to get an R1.


Also providing a safe set of rules that can figure out
trivial_relocation for an aggregate/composite should be easier.

Can you elaborate on this? (i.e.: I think you're wrong.)
The set of rules in P1144R0 section 4.4 is specifically to deal with "trivially relocatable," so they wouldn't get any shorter or simpler.  P1144 doesn't provide, and doesn't need to provide, any other set of rules to deal with "relocatable" or "nothrow relocatable," because those fall out of the existing type system completely naturally.

My continued thanks for this discussion! :)
–Arthur

Arthur O'Dwyer

unread,
Nov 13, 2018, 4:55:28 PM11/13/18
to mwoehlk...@gmail.com, std-pr...@isocpp.org
On Tue, Nov 13, 2018 at 12:48 PM Matthew Woehlke <mwoehlk...@gmail.com> wrote:
On 11/11/2018 20.35, Arthur O'Dwyer wrote:
> EWG3. Nobody should be able to warrant the trivial relocatability of class
> `C` except for class `C` itself (i.e., we do not want to see a
> customization point analogous to `std::hash`).

N leaning to A.

While this makes sense *in principle*, in practice it's not unusual to
want/need this optimization for a class which is outside of your control.

Many thanks for your !votes, even those I might argue with; I have recorded them. :)

I don't want to appear argumentative, but I do want to present my proposed workaround for dealing with this problem:

    std::vector<thirdparty::SharedPtr> vec;  // oops, doesn't get the memcpy optimization
    vec.emplace_back(...);  // oops


    template<class T> struct [[trivially_relocatable]] TR : public T { using T::T; };

    std::vector<TR<thirdparty::SharedPtr>> tvec;  // OK, gets the memcpy optimization
    tvec.emplace_back(...);  // OK

This is definitely a "workaround," not a good practice; but personally I'd rather see this workaround in a few places (for a few years) than see a customization point put into the Standard (forever).



> EWG4. A class should be able to warrant its own trivial relocatability via
> the attribute `[[trivially_relocatable]]`, as proposed in this paper.

N leaning to A.

One of the reasons we tend to talk about "destructive move" is that
there are lifetime implications. It's not clear that this can be
correctly expressed via an attribute. It seems like users would need to
call a special flavor of dtor.

I recorded this as "N", although I can revise it to "A" if you want.
The intent of EWG4 is to ask if you agree with the statement. If your opinion is that you don't want P1144's attribute because you want a special flavor of destructor instead, then that is a perfectly valid reason to vote "A". Or if you don't want P1144's attribute because you don't like attributes. Or if you don't like P1144's attribute because it's named wrong. Or really any reason. The poll is just whether you agree or disagree with the statement as written.

Personally I don't think you'll ever get a special flavor of destructor in C++. Certainly I don't know how to get that. But it's a valid motivation for anyone's "A" vote (contra to what I think Mihail was saying).

(I'm also far from convinced this is an "acceptable" use of an attribute.)

The results for EWG5 and EWG6 should give some guidance there. EWG4/EWG5 differentiate "I like your attribute approach but want to bikeshed the name"; EWG5/EWG6 differentiate "I like the general approach but want to bikeshed the choice of an attribute vs. a keyword."
As with EWG4: If you want to express "I don't think a class should be able to warrant its etc. etc. via etc. etc.," then you'd vote "A" or "SA".


> EWG6. A class should be able to warrant its own trivial relocatability as
> proposed in this paper, but we prefer to see a contextual keyword rather
> than an attribute.

Strongly N.

Again, this is too leading. The correct solution might be:

  class Foo
  {
    Foo(Foo~ other) = default; // relocating ctor
    ...
  };

...which isn't really "a contextual keyword".

More relevantly, that isn't remotely "as proposed in this paper"!  If you disagree that a class should be able to etc. etc. as proposed in this paper, then you should be voting "A" on many of these.


> EWG7. If a trait with the semantics of `is_trivially_relocatable<T>` is
> added to the `<type_traits>` header, the programmer should be permitted to
> specialize it for program-defined types (i.e., we want to see that trait
> itself become a customization point analogous to `std::hash`).

Weakly F.

This seems redundant with EWG3.

EWG3 is about the existence of some customization mechanism not controlled by the class author.
EWG7 is about the desirability of letting the user specialize anything out of <type_traits>.
(Personally, I'm "OMDB" on EWG7. See my blog for my confidently held theory of customization point design.)


> EWG8. Trivial relocatability should be assumed by default. Classes such as
> those in Appendix C
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1144r0.html#non-trivial-samples>
> should indicate their non-trivial relocatability via an opt-in mechanism.

If you *literally* meant "all" classes, vs. e.g. those that meet some
reasonable criteria, then SA leaning toward OMDB.

Yes, I did. "SA" recorded. :)
Tangentially, I am curious what you would consider "some reasonable criteria."


> EWG9. To simplify conditionally trivial relocation
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1144r0.html#sample-conditional>,
> if an attribute with the semantics of `[[trivially_relocatable]]` is added,
> it should take a boolean argument.

I'm not even going to answer this one. As others, *way* too leading as
far as assuming a particular approach which does *not* have consensus.

Abstention recorded.
The intent of EWG9 is to get feedback on whether the attribute should take a boolean argument, if the attribute is accepted. If the attribute is not accepted, then the result of EWG9 probably becomes moot. (But it might still inform a different design, or even provide a barometer for someone designing a completely different attribute for a completely different purpose.)
Some people may have strong opinions on EWG9, and I want to get that feedback sooner rather than later, hence the conditional question. (Some people may vote "SA" on EWG1 and LEWG14, indicating strong disagreement with the paper, and nevertheless have a strong opinion on EWG9!)


> LEWG13. The type trait `is_trivially_relocatable<T>` should be added to the
> `<type_traits>` header, under that exact name, as proposed in this paper.

F.

In practice, I'm not sure how useful the other two will be.

> LEWG14. We approve of a trait with the semantics of
> `is_trivially_relocatable<T>`, but possibly under a different name. (For
> example, `is_bitwise_relocatable`.)

F, I guess.

Seems a bit redundant with LEWG13, but I guess the point is for people
that want to complain about the color of the bikeshed.

Yes. LEWG13 is "we want a bikeshed of this color." LEWG14 is "we do want a bikeshed, but maybe a different color." People who don't want a bikeshed at all should vote "A, A". People who want a bikeshed but don't like the current color should vote "A, F". People who just want a bikeshed and don't care about the color should vote "F, F".

Thanks!
–Arthur

Matthew Woehlke

unread,
Nov 13, 2018, 5:01:39 PM11/13/18
to std-pr...@isocpp.org, mihailn...@gmail.com, arthur....@gmail.com
On 13/11/2018 14.24, mihailn...@gmail.com wrote:
> Matthew, the paper is not about "destructive move".

Really? Because that's exactly what uninitialized_relocate does.

> In a way the paper is "what can do after dmove has failed"

What do you mean by "failed"? Do you mean "papers taking that approach
have not been accepted", or do you mean that the code attempted a dmove
and... something happened? (It threw an exception?)

I was *in* SG17 when we reviewed the paper. I did not at all get the
impression that "destructive move" (assuming that you are implying some
specific implementation strategy, and not the general problem) was
"dead". Rather, I got the impression that this general problem is *hard*
and we aren't confident that we have seen a paper yet that adequately
deals with all of the tricky details. *Including* P1144. (Of note: folks
were concerned about allocators.)

I wasn't present for the presentation of other papers in this area, so I
can't be sure why they failed, but again, my impression from SG17 was
that they failed due to tricky details, not because the overall
approaches were unacceptable.

The approach taken in P1144 feels extremely magical. It proposes an
*attribute* that allows the compiler leeway to implement a particular
library function in a way that has somewhat profound implications on the
memory model. I am... unconvinced that an attribute is the right way to
accomplish that, nor that there is not value in having a "first class"
destroying ctor.

--
Matthew

Matthew Woehlke

unread,
Nov 13, 2018, 5:40:34 PM11/13/18
to std-pr...@isocpp.org, Arthur O'Dwyer
On 13/11/2018 16.55, Arthur O'Dwyer wrote:
>> N leaning to A.
>
> I recorded this as "N", although I can revise it to "A" if you want.

That's fine; any "X leaning to Y" means that in a real straw poll where
I can't qualify, I would *probably* vote 'X' :-).

Anyway, IMHO the "votes" on some of the leading questions aren't very
meaningful anyway. (At least mine aren't :-).)

Since I'm rationalizing... several votes of that nature were in the line
of "I am not really *personally* on board with this approach, but not
enough to try to block it if the rest of EWG seems happy".

> Personally I don't think you'll ever get a special flavor of destructor in
> C++. Certainly I don't know how to get that. But it's a valid motivation
> for anyone's "A" vote (*contra* to what I think Mihail was saying).

Sure. As noted in my reply, I wasn't present for discussion of any such
papers, but my impression in SG17 was that the reason we haven't
approved any such approach isn't due to *philosophical* dislike, but
because the details are really hard, and no paper has yet satisfactorily
dealt with all such details.

>> EWG6. A class should be able to warrant its own trivial relocatability as
>>> proposed in this paper, but we prefer to see a contextual keyword rather
>>> than an attribute.
>>
>> Again, this is too leading. [...]
>
> More relevantly, that isn't remotely "as proposed in this paper"! If you
> disagree that a class should be able to etc. etc. *as proposed in this
> paper,* then you should be voting "A" on many of these.

Well, sure, but again my impression from SG17 is that the design space
is still open. My voting is very much based on that. (And again, I'm not
*strongly* opposed enough to try to kill this approach if it seems
viable. Wisteria may not be my first choice, but we need the bikeshed
more than we need it painted my favorite shade of glaucous.)

>>> EWG7. If a trait with the semantics of
>>> `is_trivially_relocatable<T>` is added to the `<type_traits>`
>>> header, the programmer should be permitted to specialize it for
>>> program-defined types (i.e., we want to see that trait itself
>>> become a customization point analogous to `std::hash`).
>>
>> Weakly F.
>>
>> This seems redundant with EWG3.
>
> EWG3 is about the existence of *some* customization mechanism not
> controlled by the class author.
> EWG7 is about the desirability of letting the user specialize anything out
> of <type_traits>.
> (Personally, I'm "OMDB" on EWG7. See my blog
> <https://quuxplusone.github.io/blog/tags/#customization-points> for my
> confidently held theory of customization point design.)

Granted. I meant more along the lines of, if EWG3 "passes", this becomes
irrelevant.

I also don't warrant that EQG7 is the *best* customization point, hence
why I am only *weakly* in favor. It's better than nothing, and you
didn't propose alternatives :-).

>>> EWG8. Trivial relocatability should be assumed by default.
>>> Classes such as those in Appendix C should indicate their
>>> non-trivial relocatability via an opt-in mechanism.
>>
>> If you *literally* meant "all" classes, vs. e.g. those that meet some
>> reasonable criteria, then SA leaning toward OMDB.
>
> Yes, I did. "SA" recorded. :)
>
> Tangentially, I am curious what you would consider "some reasonable
> criteria."

P1144§3 seems plausible, at least at first glance (i.e. with the caveat
that I haven't spent a ton of time trying to break those criteria).
Given that, TBH I was a bit surprised by this question. (Unless, as
noted, I am misreading it...)

>>> EWG9. To simplify conditionally trivial relocation, if an
>>> attribute with the semantics of `[[trivially_relocatable]]` is
>>> added, it should take a boolean argument.
>>
>> I'm not even going to answer this one.

Actually, I'll take that back. *If* we go with an attribute (and IMHO
that remains a *very* big 'if'), then I think it does make sense to have
a way to explicitly force it off → F, but weakly.

>>> LEWG14. We approve of a trait with the semantics of
>>> `is_trivially_relocatable<T>`, but possibly under a different name. (For
>>> example, `is_bitwise_relocatable`.)
>>
>> F, I guess.

(I should note that some folks have been complaining that reflection
will make type traits moot. I suppose to that extent, a) I want the
shed, but b) I don't particularly care if it's a bike shed (type trait)
or a tool shed (some reflection-based mechanism), just as long as there
is *some* way I can ask if a type is trivially relocatable.)

--
Matthew

Edward Catmur

unread,
Nov 14, 2018, 12:31:40 AM11/14/18
to ISO C++ Standard - Future Proposals
I'd like to preface my votes with some justification for my views.

Firstly, I believe that the concept of trivial relocatability implies the concept of non-trivial relocatability, and not just in the move-construct-and-destruct sense, but via some as yet unspecified mechanism that does not require two objects to exist at the same time - (very) tentatively a memcpy-and-noexcept-repair. This means that we should leave open the path toward such a mechanism.

Secondly, lifetime is *serious* - it accounts for many of the bugs that afflict experienced programmers. In particular I'm worried about behavior classes that own callbacks (or event handlers), since these are typically lambdas capturing `this`, and such classes may well be stored in containers and thus subject to relocation. It should never be easy to make claims about the lifetime behavior of another class. With regards to warranting trivial relocatability of one's own class, this should only be possible if the bases and members are themselves (warranted to be) trivially relocatable; the wrapper class presented above is too prone to abuse to be allowed. There is still an escape hatch to impose trivial relocatability on a third-party class - use `aligned_storage` and construct, move, copy and destruct as appropriate the wrapped class. For the danger involved, this is not an unreasonable amount of work to impose on the programmer.

That is, a class should only be able to warrant its own trivial relocatability if it *would* be trivially relocatable but for the presence of its own user-defined special member functions. This should be similar to and familiar from the concept of explicitly defaulting move constructor, etc. Together, this suggests that the appropriate syntax for warranting trivial relocatability or otherwise should be a special member function that can be defaulted or deleted, but not user-supplied as yet: `RELOCATE = (default|delete);` where:
* RELOCATE is a bikeshed placeholder for a special member;
* `default` means that the class is trivially relocatable if all its bases and members are trivially relocatable, and otherwise is not (there is no way to "force" trivial relocatability);
* `delete` means that the class is not trivially relocatable, even if it would otherwise qualify. (The class can still be relocated by move-construct-and-destruct.)
The advantage of this syntax would be that the path to destructive move would be open: once the semantics are understood, convert RELOCATE to a special member *function* and allow the user to provide a body. That said, a contextual keyword wouldn't be too bad, and even the attribute as proposed would be better than not going forward - but in either case, it should still not be possible to force trivial relocatability on another class by wrapping it, so the attribute or contextual keyword should only counteract the presence of user-provided or deleted special member functions of that class.

And thanks for working on this and for canvassing opinion here.

EWG1. We approve of the general idea that user-defined classes should be able to warrant their own trivial relocatability via a standard mechanism.

SA, except when their bases and members are themselves relocatable, in which case SF. (The "escape hatch" is to use `aligned_storage`.)
 
EWG2. We approve of the general idea that user-defined classes which follow the Rule of Zero should inherit the trivial relocatability of their bases and members.
 
SF

EWG3. Nobody should be able to warrant the trivial relocatability of class `C` except for class `C` itself (i.e., we do not want to see a customization point analogous to `std::hash`).

SF
 
EWG4. A class should be able to warrant its own trivial relocatability via the attribute `[[trivially_relocatable]]`, as proposed in this paper.

A (and SA if its bases and members are not trivially relocatable, per EWG1) - I don't think an attribute is appropriate for modifying lifetime behavior.
 
EWG5. A class should be able to warrant its own trivial relocatability via some attribute, but not necessarily under that exact name.

A (and SA), per EWG4
 
EWG6. A class should be able to warrant its own trivial relocatability as proposed in this paper, but we prefer to see a contextual keyword rather than an attribute.

F but only under the conditions described per EWG1, and in that a contextual keyword is better than an attribute, but a special member (defaultable/deletable only, for now) would be better still.
 
EWG7. If a trait with the semantics of `is_trivially_relocatable<T>` is added to the `<type_traits>` header, the programmer should be permitted to specialize it for program-defined types (i.e., we want to see that trait itself become a customization point analogous to `std::hash`).

SA
 
EWG8. Trivial relocatability should be assumed by default. Classes such as those in Appendix C should indicate their non-trivial relocatability via an opt-in mechanism.

SA
 
EWG9. To simplify conditionally trivial relocation, if an attribute with the semantics of `[[trivially_relocatable]]` is added, it should take a boolean argument.

A
 
LEWG10. The algorithm `uninitialized_relocate(first, last, d_first)` should be added to the `<memory>` header, as proposed in this paper.

F
 
LEWG11. The type trait `is_relocatable<T>` should be added to the `<type_traits>` header, as proposed in this paper.

F
 
LEWG12. If `is_relocatable<T>` is added, then we should also add `is_nothrow_relocatable<T>`, as proposed in this paper.

F
 
LEWG13. The type trait `is_trivially_relocatable<T>` should be added to the `<type_traits>` header, under that exact name, as proposed in this paper.

F
 
LEWG14. We approve of a trait with the semantics of `is_trivially_relocatable<T>`, but possibly under a different name. (For example, `is_bitwise_relocatable`.)

F, but I'm happy with the proposed name.
 
LEWG15. If `is_trivially_relocatable<T>` is added, under that exact name, then the type trait `is_trivially_swappable<T>` should also be added to the `<type_traits>` header.

 F, but it doesn't seem essential, as discussed in the paper.

Arthur O'Dwyer

unread,
Nov 14, 2018, 1:06:57 AM11/14/18
to std-pr...@isocpp.org
On Wed, Nov 14, 2018 at 12:31 AM Edward Catmur <e...@catmur.co.uk> wrote:
I'd like to preface my votes with some justification for my views.

Firstly, I believe that the concept of trivial relocatability implies the concept of non-trivial relocatability, and not just in the move-construct-and-destruct sense, but via some as yet unspecified mechanism that does not require two objects to exist at the same time - (very) tentatively a memcpy-and-noexcept-repair. This means that we should leave open the path toward such a mechanism.

(P1144 essentially assumes that no such mechanism will ever be forthcoming. But I'm aware of the memcpy-and-fixup idea.)


Secondly, lifetime is *serious* - it accounts for many of the bugs that afflict experienced programmers. In particular I'm worried about behavior classes that own callbacks (or event handlers), since these are typically lambdas capturing `this`, and such classes may well be stored in containers and thus subject to relocation. It should never be easy to make claims about the lifetime behavior of another class. With regards to warranting trivial relocatability of one's own class, this should only be possible if the bases and members are themselves (warranted to be) trivially relocatable; the wrapper class presented above is too prone to abuse to be allowed. There is still an escape hatch to impose trivial relocatability on a third-party class - use `aligned_storage` and construct, move, copy and destruct as appropriate the wrapped class. For the danger involved, this is not an unreasonable amount of work to impose on the programmer.

That is, a class should only be able to warrant its own trivial relocatability if it *would* be trivially relocatable but for the presence of its own user-defined special member functions.

Over on the Clang pull request, rjmccall is taking a similar stand, and I'm having trouble understanding why it's desirable. The way I see it, the whole point of the type-trait is so that library authors can inspect it and make correct decisions about the trivial-relocatability of their wrapper classes. (EWG9 is related.) Obviously if you want your wrapper class merely to propagate the trivial-relocatability of all its bases and members, then you should be allowed to do that; but I don't want to prohibit people from writing e.g.

    struct [[trivially_relocatable]] Widget {
        boost::shared_ptr<int> sptr;  // assume Boost won't catch up for a little while, and/or we're stuck on an old version of Boost
    };

or e.g.

    struct [[trivially_relocatable]] BatteriesIncluded {
        char heap[1000];
        std::vector<int, offset_ptr_allocator<int>> vec;  // all pointers are stored as offsets into 'heap'
        BatteriesIncluded(BatteriesIncluded&&);  // very complicated fixup goes here
    };

If I understand your statement correctly, you do want to prohibit people from writing either of these things.
(And over on the pull request, I understand rjmccall as saying that maybe we should allow people to write these things but quietly ignore the attribute, unless they "double-opt-in" by writing e.g. `class [[trivially_relocatable_bikeshed!]] Widget`. I have a hard time imagining when I'd ever want to opt in without double-opting-in.)


This should be similar to and familiar from the concept of explicitly defaulting move constructor, etc. Together, this suggests that the appropriate syntax for warranting trivial relocatability or otherwise should be a special member function that can be defaulted or deleted, but not user-supplied as yet: `RELOCATE = (default|delete);` where:
* RELOCATE is a bikeshed placeholder for a special member;
* `default` means that the class is trivially relocatable if all its bases and members are trivially relocatable, and otherwise is not (there is no way to "force" trivial relocatability);
* `delete` means that the class is not trivially relocatable, even if it would otherwise qualify. (The class can still be relocated by move-construct-and-destruct.)

I don't see how you'd implement a trivially relocatable `unique_ptr` using only these features. ...Which is fine — maybe it won't be possible to write `unique_ptr` in standard C++, but vendors will use secret sauce to achieve it anyway. P1144R0 does emphasize that the type-trait would be useful even without any standard attribute.
Unless you mean that `RELOCATE=default` would mean "memcpy me" even in the presence of a non-trivial move-constructor and destructor. My kneejerk reaction was that that would go against the spirit of what "=default" usually means in C++. That is,

    struct List : private ListNode {
        ListNode *head, *tail;
        List(List&& rhs) : head(rhs.head), tail(rhs.tail) { head->prev = this; tail->next = this; }
        ~List();
        RELOCATE = default;  // oops, this would be a bug
    };

So the default that happens when the user doesn't provide any definition of `RELOCATE` would have to be something like "no RELOCATE exists," and adding an explicit `RELOCATE = default;` to an existing class might actually break its behavior.
It might be doable, but I don't think it'd be easy.
And you'd still lack any way to express `Widget` and `BatteriesIncluded`, which I think is a problem for real codebases. (Especially `Widget`.)


EWG1. We approve of the general idea that user-defined classes should be able to warrant their own trivial relocatability via a standard mechanism.

SA, except when their bases and members are themselves relocatable, in which case SF. (The "escape hatch" is to use `aligned_storage`.)

Recorded as "SA".
 
EWG4. A class should be able to warrant its own trivial relocatability via the attribute `[[trivially_relocatable]]`, as proposed in this paper.

A (and SA if its bases and members are not trivially relocatable, per EWG1) - I don't think an attribute is appropriate for modifying lifetime behavior.

Recorded as "A".

Thanks!
–Arthur

Matthew Woehlke

unread,
Nov 14, 2018, 10:57:38 AM11/14/18
to std-pr...@isocpp.org, Edward Catmur
On 14/11/2018 00.31, Edward Catmur wrote:
> In particular I'm worried about behavior classes that own callbacks
> (or event handlers), since these are typically lambdas capturing
> `this`, and such classes may well be stored in> containers and thus
> subject to relocation.
Either such classes must have non-trivial copy/move ctors, and are thus
ineligible for being trivially relocatable, or they are broken even
without relocation (because a plain old move/copy ctor will also break
them). In fact, storing them in containers is probably already broken.
(Maybe not map, but definitely vector or flat_map.)

> With regards to warranting trivial relocatability of one's own class,
> this should only be possible if the bases and members are themselves
> (warranted to be) trivially relocatable
For default behavior, definitely agreed. However, I believe there are
known cases when an object may *appear* to not be trivially relocatable
when actually it is?

I suppose you are worried about a class that was warranted as trivially
relocatable changing so that it no longer is. This sounds like a problem
to be solved by tooling, however. We can always add compiler warnings if
the author is overriding the compiler's guess.

--
Matthew

Arthur O'Dwyer

unread,
Nov 14, 2018, 11:14:08 AM11/14/18
to std-pr...@isocpp.org
Aha. This sounds like a FAQ that I tried to address in a blog post a while back:
Is that post relevant to anyone's concerns?

–Arthur

mihailn...@gmail.com

unread,
Nov 14, 2018, 3:06:53 PM11/14/18
to ISO C++ Standard - Future Proposals
To be honest probably being able to mark members as well, will be the best option 

 struct [[trivially_relocatable]] Widget {
        [[trivially_relocatable]]  boost::shared_ptr<int> sptr;  // trust me!
    };

 struct [[trivially_relocatable]] BatteriesIncluded {
        char heap[1000];
        [[trivially_relocatable]] std::vector<int, offset_ptr_allocator<int>> vec;  // trust me!
        BatteriesIncluded(BatteriesIncluded&&);  // very complicated fixup goes here
    };

This way we are safe to compile only when all members and subclasses are trivially_relocatable (either implicitly or with a tag)

Declaring a member does not make it (the member variable) trivially_relocatable (dtor still called, etc), but will shut the compiler complaining much like mutable does

olee...@gmail.com

unread,
Nov 14, 2018, 6:17:35 PM11/14/18
to ISO C++ Standard - Future Proposals
EWG1. We approve of the general idea that user-defined classes should be able to warrant their own trivial relocatability via a standard mechanism.

SF

EWG2. We approve of the general idea that user-defined classes which follow the Rule of Zero should inherit the trivial relocatability of their bases and members.

SF

EWG3. Nobody should be able to warrant the trivial relocatability of class `C` except for class `C` itself (i.e., we do not want to see a customization point analogous to `std::hash`).

For

EWG6. A class should be able to warrant its own trivial relocatability as proposed in this paper, but we prefer to see a contextual keyword rather than an attribute.

For

EWG8. Trivial relocatability should be assumed by default. Classes such as those in Appendix C should indicate their non-trivial relocatability via an opt-in mechanism.

Against

LEWG10. The algorithm `uninitialized_relocate(first, last, d_first)` should be added to the `<memory>` header, as proposed in this paper.

Against
 - The suggested semantics seem questionable in the face of a possible exception in the middle of the loop. But rather than arguing about the specification, I think it should be dropped from the paper. The experts who would use this could easily roll their own anyway.

LEWG12. If `is_relocatable<T>` is added, then we should also add `is_nothrow_relocatable<T>`, as proposed in this paper.

For

LEWG13. The type trait `is_trivially_relocatable<T>` should be added to the `<type_traits>` header, under that exact name, as proposed in this paper.

SF

LEWG14. We approve of a trait with the semantics of `is_trivially_relocatable<T>`, but possibly under a different name. (For example, `is_bitwise_relocatable`.)

For

Don't really care about the rest (neutral).

Matthew Woehlke

unread,
Nov 15, 2018, 10:51:11 AM11/15/18
to std-pr...@isocpp.org, olee...@gmail.com
On 14/11/2018 18.17, olee...@gmail.com wrote:
> LEWG10. The algorithm `uninitialized_relocate(first, last, d_first)` should
> be added to the `<memory>` header, as proposed in this paper.
>
> *Against*
> - The suggested semantics seem questionable in the face of a possible
> exception in the middle of the loop. But rather than arguing about the
> specification, I think it should be dropped from the paper. The experts who
> would use this could easily roll their own anyway.

I don't think that's true. As I understand it, this function is, in some
sense, the sole reason the proposal has value. Specifically, it is
specially blessed as being able to actually perform a memcpy but still
DTRT WRT the memory model.

Without it, "the experts who would use this" must continue to rely on
UB, which defeats one of the main objectives of the proposal. (Am I
missing something? If so, please correct me!)

(That said, "against because I don't trust the semantics in the face of
exceptions" is useful feedback.)

--
Matthew

olee...@gmail.com

unread,
Nov 15, 2018, 5:33:44 PM11/15/18
to ISO C++ Standard - Future Proposals, olee...@gmail.com
Well, in that case it's not enough. We need the ability to relocate to a destination range that is only partially uninitialized, and backwards too. (Consider vector erase and insert.) So I would continue to rely on UB regardless.

Arthur O'Dwyer

unread,
Nov 15, 2018, 5:43:56 PM11/15/18
to std-pr...@isocpp.org
On Thu, Nov 15, 2018 at 5:33 PM <olee...@gmail.com> wrote:
On Thursday, November 15, 2018 at 4:51:11 PM UTC+1, Matthew Woehlke wrote:
On 14/11/2018 18.17, olee...@gmail.com wrote:
>  - The suggested semantics seem questionable in the face of a possible
> exception in the middle of the loop. But rather than arguing about the
> specification, I think it should be dropped from the paper. The experts who
> would use this could easily roll their own anyway.

I don't think that's true. As I understand it, this function is, in some
sense, the sole reason the proposal has value. Specifically, it is
specially blessed as being able to actually perform a memcpy but still
DTRT WRT the memory model.

The intent of P1144R0 is that `memcpy` itself would be the "specially blessed" library function: it's defined to Do The Right Thing for trivially relocatable types (by magic; but not really any more magic than it already possesses for trivial types). P1144's `uninitialized_relocate` is a convenient high-level entry point for when you don't know if it's safe to memcpy or not and you just want the library to dispatch to the appropriate low-level function (memcpy, or loop over ctor/dtor).

Without it, "the experts who would use this" must continue to rely on
UB, which defeats one of the main objectives of the proposal. (Am I
missing something? If so, please correct me!) [...]

Well, in that case it's not enough. We need the ability to relocate to a destination range that is only partially uninitialized, and backwards too. (Consider vector erase and insert.) So I would continue to rely on UB regardless.

The intent of P1144R0 is that you would be able to use `memcpy` without UB. It's a bit handwavey... but then so is almost everything related to UB. (For example: if it's okay to `memcpy` a trivially relocatable type, is it also okay to type-pun it to an array of char and then copy the chars in a loop? I'd think "yes", but I wouldn't care if the answer were "no". Even if we go so far as to say that it's UB even to memcpy trivially relocatable types, it would still be super useful to have the type-trait that accurately reports whether memcpy would, physically, accomplish our codegen goal, even if it is technically still UB. :))

–Arthur

Itaj Sherman

unread,
Nov 16, 2018, 10:43:36 AM11/16/18
to ISO C++ Standard - Future Proposals
You should have some function in the standard that says it can do the copy, whether memcpy or another, at the least 'implementation defined'.
Otherwise this would be terrible for people (like me) who are not extremely versed in the standard but do need to be able to read it.
If I didn't read this conversation, and eventually I read in the standard about relocation, but there's no function that can actually do the copy, I would just misunderstand it, possibly go look for information, and most possibly not get the right answer.
 
–Arthur

 itaj

Nicolas Lesser

unread,
Nov 16, 2018, 11:06:34 AM11/16/18
to std-pr...@isocpp.org
Here's my 2c/.
 
EWG1. We approve of the general idea that user-defined classes should be able to warrant their own trivial relocatability via a standard mechanism.
F 

EWG2. We approve of the general idea that user-defined classes which follow the Rule of Zero should inherit the trivial relocatability of their bases and members.
SF 

EWG3. Nobody should be able to warrant the trivial relocatability of class `C` except for class `C` itself (i.e., we do not want to see a customization point analogous to `std::hash`).
SF 

EWG4. A class should be able to warrant its own trivial relocatability via the attribute `[[trivially_relocatable]]`, as proposed in this paper.
N

EWG5. A class should be able to warrant its own trivial relocatability via some attribute, but not necessarily under that exact name.
N

EWG6. A class should be able to warrant its own trivial relocatability as proposed in this paper, but we prefer to see a contextual keyword rather than an attribute.
A 

EWG7. If a trait with the semantics of `is_trivially_relocatable<T>` is added to the `<type_traits>` header, the programmer should be permitted to specialize it for program-defined types (i.e., we want to see that trait itself become a customization point analogous to `std::hash`).
SA 

EWG8. Trivial relocatability should be assumed by default. Classes such as those in Appendix C should indicate their non-trivial relocatability via an opt-in mechanism.
SA 

EWG9. To simplify conditionally trivial relocation, if an attribute with the semantics of `[[trivially_relocatable]]` is added, it should take a boolean argument.
N 

Thiago Macieira

unread,
Nov 18, 2018, 1:24:40 PM11/18/18
to std-pr...@isocpp.org
This email is just the poll answers. I'm reading the rest of the thread (as
I'm a week late) before providing comments on the paper.

On Sunday, 11 November 2018 17:35:39 PST Arthur O'Dwyer wrote:
> EWG1. We approve of the general idea that user-defined classes should be
> able to warrant their own trivial relocatability via a standard mechanism.

Strong For.

> EWG2. We approve of the general idea that user-defined classes which follow
> the Rule of Zero
> <https://web.archive.org/web/20130607234833/http://flamingdangerzone.com/cxx
> 11/2012/08/15/rule-of-zero.html> should inherit the trivial relocatability
> of their bases and members.

Strong For.

> EWG3. Nobody should be able to warrant the trivial relocatability of class
> `C` except for class `C` itself (i.e., we do not want to see a
> customization point analogous to `std::hash`).

Neutral. I lean towards "For", but I can see why someone may want to do this
specifically on certain translation units or for certain restricted uses, and
having no argument as to why they shouldn't, I can't give an opinion on either
way.

> EWG4. A class should be able to warrant its own trivial relocatability via
> the attribute `[[trivially_relocatable]]`, as proposed in this paper.

Strong For.

> EWG5. A class should be able to warrant its own trivial relocatability via
> some attribute, but not necessarily under that exact name.

Strong For.

> EWG6. A class should be able to warrant its own trivial relocatability as
> proposed in this paper, but we prefer to see a contextual keyword rather
> than an attribute.

Neutral.

> EWG7. If a trait with the semantics of `is_trivially_relocatable<T>` is
> added to the `<type_traits>` header, the programmer should be permitted to
> specialize it for program-defined types (i.e., we want to see that trait
> itself become a customization point analogous to `std::hash`).

Against, in spite of EWG3's justification. Even if outside-of-class
declaration of relocatability is permitted, I don't think it should be by
specialisation of the <type_traits> type.

> EWG8. Trivial relocatability should be assumed by default. Classes such as
> those in Appendix C
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1144r0.html#non-tr
> ivial-samples> should indicate their non-trivial relocatability via an
> opt-in mechanism.

Strong against.

> EWG9. To simplify conditionally trivial relocation
> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1144r0.html#sample
> -conditional>, if an attribute with the semantics of
> `[[trivially_relocatable]]` is added, it should take a boolean argument.

For.

> LEWG10. The algorithm `uninitialized_relocate(first, last, d_first)` should
> be added to the `<memory>` header, as proposed in this paper.

No opinion (abstention).

> LEWG11. The type trait `is_relocatable<T>` should be added to the
> `<type_traits>` header, as proposed in this paper.

For. It complements, but as it's defined as just anding two existing traits,
its absence would not hinder any development.

> LEWG12. If `is_relocatable<T>` is added, then we should also add
> `is_nothrow_relocatable<T>`, as proposed in this paper.

Strong for.

> LEWG13. The type trait `is_trivially_relocatable<T>` should be added to the
> `<type_traits>` header, under that exact name, as proposed in this paper.

Strong for.

> LEWG14. We approve of a trait with the semantics of
> `is_trivially_relocatable<T>`, but possibly under a different name. (For
> example, `is_bitwise_relocatable`.)

Strong for.

> LEWG15. If `is_trivially_relocatable<T>` is added, under that exact name,
> then the type trait `is_trivially_swappable<T>` should also be added to the
> `<type_traits>` header.

For.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center



Thiago Macieira

unread,
Nov 18, 2018, 2:06:18 PM11/18/18
to std-pr...@isocpp.org
On Sunday, 18 November 2018 10:24:36 PST Thiago Macieira wrote:
> > EWG9. To simplify conditionally trivial relocation
> > <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1144r0.html#samp
> > le -conditional>, if an attribute with the semantics of
> > `[[trivially_relocatable]]` is added, it should take a boolean argument.
>
> For.

Sorry, revising to Strong For. See my answer to Edward's email for rationale.

Thiago Macieira

unread,
Nov 18, 2018, 2:24:29 PM11/18/18
to std-pr...@isocpp.org
On Tuesday, 13 November 2018 21:31:40 PST Edward Catmur wrote:
> I'd like to preface my votes with some justification for my views.
>
> Firstly, I believe that the concept of trivial relocatability implies the
> concept of non-trivial relocatability, and not just in the
> move-construct-and-destruct sense, but via some as yet unspecified
> mechanism that does not require two objects to exist at the same time -
> (very) tentatively a memcpy-and-noexcept-repair. This means that we should
> leave open the path toward such a mechanism.

I really don't see how that would exist in a non-limited fashion. The example
of the short string with a pointer to self might be one, but any non-trivial
implementation could fall outside of what the repair operation is permitted to
do. Specifically: is the repair operation allowed to access the moved-from
object, after the memcpy? If not, libstdc++'s new std::string would fall
outside the parameters.

> Secondly, lifetime is *serious* - it accounts for many of the bugs that
> afflict experienced programmers. In particular I'm worried about behavior
> classes that own callbacks (or event handlers), since these are typically
> lambdas capturing `this`, and such classes may well be stored in containers
> and thus subject to relocation.

I'm with Matthew's answer here: such types are either broken or already not
trivially relocatable due to the presence of user-defined copy and/or move
constructors.

> That is, a class should only be able to warrant its own trivial
> relocatability if it *would* be trivially relocatable but for the presence
> of its own user-defined special member functions.

But this is an interesting concept. If I have two classes A and B, with A a
base class of B, a new version of A may change whether it is trivially
relocatable. What does this mean for B?

If A wasn't trivially relocatable but now is, B could benefit from the
improvement but requires manual intervention to declare so. If A was trivially
relocatable and B added the attribute, then this is actually worse: now we're
performing trivial relocations where we shouldn't.

Therefore, it needs to be possible for class B to declare that it is
(trivially) relocatable if its base classes are, in spite of it adding one a
user-defined move constructor or destructor. This is achieavable with an
attribute with parameter, as in:

class [[trivially_relocatable(std::is_trivially_relocatable_v<A>)]] B : A
{ ... };

Of course, immediately upon seeing this, we desire a shorthand for depending
on other types' relocatability. Moreover, if this is going to allow for
complex expressions, it's also a good reason to explore either a contextual
keyword or a different mechanism.

> * RELOCATE is a bikeshed placeholder for a special member;
> * `default` means that the class is trivially relocatable if all its bases
> and members are trivially relocatable, and otherwise is not (there is no
> way to "force" trivial relocatability);

That I disagree with, though not strongly so.

> * `delete` means that the class is not trivially relocatable, even if it
> would otherwise qualify. (The class can still be relocated by
> move-construct-and-destruct.)

What would be the use-case for this? Can you think of an example of such a
class, one that isn't broken when placed in a container or copied around?

> The advantage of this syntax would be that the path to destructive move
> would be open: once the semantics are understood, convert RELOCATE to a
> special member *function* and allow the user to provide a body.

In the previous thread, I was for the destructive move solution. But right
now, I am failing to come up with a reasonable case where we'd need that. We'd
need a syntax for the caller to perform a destructive move, as

x = std::move(y);

won't be it. And

x = function_returning_by_value();

doesn't need it, after mandatory copy elision. So what are the use-cases for
this new syntax? The best I can think of is:
std::string x;
if (condition) {
std::string y = something();
if (condition2)
y += something_else();
x = std::relocate(y);
}

This is a contrived example that can be best solved by removing the y variable
in the first place, but a large & complex function could maybe use to simplify
refactoring. But this opens an even bigger can of worms, as the y variable can
no longer be used after the std::relocate call.

Thiago Macieira

unread,
Nov 18, 2018, 2:39:20 PM11/18/18
to std-pr...@isocpp.org
On Sunday, 18 November 2018 11:24:26 PST Thiago Macieira wrote:
> And
>
> x = function_returning_by_value();
>
> doesn't need it, after mandatory copy elision.

Correction:

auto x = function_returning_by_value();

In order for the called function to return by value, an area of scratch space
must be provided as an implicit parameter and the callee will construct the
returned value in place. I don't remember if implementations are allowed to
pass the address of a temporary instead of x's, but if they are, we can more
easily solve this by forbidding that technique than adding destructive move.

Arthur O'Dwyer

unread,
Nov 18, 2018, 7:44:17 PM11/18/18
to std-pr...@isocpp.org
On Sun, Nov 18, 2018 at 2:24 PM Thiago Macieira <thi...@macieira.org> wrote:
On Tuesday, 13 November 2018 21:31:40 PST Edward Catmur wrote:
> That is, a class should only be able to warrant its own trivial
> relocatability if it *would* be trivially relocatable but for the presence
> of its own user-defined special member functions.

But this is an interesting concept. If I have two classes A and B, with A a
base class of B, a new version of A may change whether it is trivially
relocatable. What does this mean for B? [...snip...]

I think the part I snipped was going down a wrong path due to a faulty assumption somewhere. This weekend I implemented the [[clang::maybe_trivially_relocatable]] attribute, which is (I think) what Edward was describing, and also what (I think) John McCall was asking for on the Clang review.

The idea is that there are two levels of "opt-in-ness."
The first level, [[clang::maybe_trivially_relocatable]], means "I warrant that even though I may have user-provided, non-defaulted, special member functions, I have designed them so that my relocation operation will not do anything substantially different from memberwise relocation." So if all of my member+base subobjects are trivially relocatable (and not mutable and not volatile), then I myself will be trivially relocatable.
The second level, [[clang::trivially_relocatable]], means "I warrant that even though I may have user-provided, non-defaulted, special member functions, and even though I may have non-trivially relocatable (or mutable or volatile) subobjects, I have designed them so that my relocation operation will not do anything substantially different from memcpy." So I myself will be trivially relocatable no matter what my subobjects claim about themselves. 

So, Thiago, I would interpret your scenario with A and B as meaning one or the other of the following scenarios:

Scenario 1.
    struct A { ... };
    struct B : public A { int m; };  // Rule of Zero

Scenario 2.
    struct A { ... };
    struct [[maybe_trivially_relocatable]] B : public A { int m; B(B&&); ~B(); };  // "B's relocate operation is tantamount to memberwise relocation"


If A wasn't trivially relocatable but now is, B could benefit from the
improvement but requires manual intervention to declare so.

I don't see any situation in which this would happen.
In Scenario 1, if A becomes trivially relocatable, then so does B, because B follows the Rule of Zero.
In Scenario 2, if A becomes trivially relocatable, then so does B, because B has the "first-level" attribute.
 
If A was trivially
relocatable and B added the attribute, then this is actually worse: now we're
performing trivial relocations where we shouldn't.

Here I agree with you (but disagree that it's a problem in practice — in fact I think it is a "solution" in practice).
Scenario 3:
    struct A { ... };
    struct [[trivially_relocatable]] B : public A { int m; B(B&&); ~B(); };  // "B's relocate operation is tantamount to memcpy"

Here, B is taking full responsibility for its own behavior. If B wants its behavior to be conditional on A's behavior, then B must express that logic in code:

    struct A { ... };
    template<bool> struct B_relocate_base : public A { int m; B_relocate_base(B_relocate_base&&); ~B_relocate_base(); };
    template<> struct [[trivially_relocatable]] B_relocate_base<true> : public A { int m; B_relocate_base(B_relocate_base&&); ~B_relocate_base(); };
    struct B : public B_relocate_base<std::is_trivially_relocatable_v<A>> {};  // Rule of Zero

This is how I originally implemented my libc++ patch which (as of this writing) is still live on Godbolt. (I plan to try to replace it with [[maybe_trivially_relocatable]] in as many places as possible, maybe as soon as tonight, so that we can get some experience with that.)

This style involves a bit of metaprogramming, and is kind of cumbersome, but it has the big benefit that we can look at B in isolation and know that it is trivially relocatable in exactly the right cases. For library types with very deeply nested inheritance graphs, such as `optional` and `variant`, I think this is important. In fact, I have not figured out any way to implement `optional` using only the [[maybe_trivially_relocatable]] attribute. I think it needs the power of "second-level" [[trivially_relocatable]].


Therefore, it needs to be possible for class B to declare that it is
(trivially) relocatable if its base classes are, in spite of it adding one a
user-defined move constructor or destructor. This is achieavable with an
attribute with parameter, as in:

  class [[trivially_relocatable(std::is_trivially_relocatable_v<A>)]] B : A
  { ... };

Of course, immediately upon seeing this, we desire a shorthand for depending
on other types' relocatability. Moreover, if this is going to allow for
complex expressions, it's also a good reason to explore either a contextual
keyword or a different mechanism.

My preferred mechanism is still the one shown above, `B_relocate_base<bool>`. But you have 100% correctly described the thought-process that led to that straw poll question about taking a boolean parameter.

The other reason a boolean parameter might be desired is for things like

    template<class T>
    class [[maybe_trivially_relocatable]] vector {
        some members;
    #ifdef _LIBCPP_DEBUG
        vector(vector&& rhs) { some instrumentation; }
        ~vector() { some instrumentation; }
    #endif
    };

As written, this is wrong.
If we use the explicit __vector_relocate_base trick, then we get the correct behavior for free.
Using [[maybe_trivially_relocatable]], we'd have to write something like

    template<class T>
    class
    #ifndef _LIBCPP_DEBUG
        [[maybe_trivially_relocatable]]
    #endif
    vector {
        some members;
    #ifdef _LIBCPP_DEBUG
        vector(vector&& rhs) { some instrumentation; }
        ~vector() { some instrumentation; }
    #endif
    };


> * RELOCATE is a bikeshed placeholder for a special member;
> * `default` means that the class is trivially relocatable if all its bases
> and members are trivially relocatable, and otherwise is not (there is no
> way to "force" trivial relocatability);

That I disagree with, though not strongly so.

I now strongly disagree with this, unless somebody can show me how to implement `std::optional<A>` so that it will inherit the trivial relocatability of `A`, without any "forcing."  I have tried and failed with libc++'s optional.
Part of the philosophical problem is that `optional` implements "destructibility" at a completely different level of the inheritance hierarchy than "move-constructibility." So in order to make all of `optional`'s base classes trivially relocatable, we essentially have to lie to the compiler and pretend that e.g. __optional_destructible_base is "trivially relocatable" when in fact it's not.  (In fact, because of the union, it is not even move-constructible! I think that is the practical problem I'm hitting.)  I would strongly prefer to have the most derived class, `optional`, take responsibility for all of its behavior as a package deal, without having to saddle every base class with a [[maybe_trivially_relocatable]] attribute which is actually a lie in most cases.

So, having investigated this [[maybe_trivially_relocatable]] attribute a little bit, I am currently of the opinion that we still need [[trivially_relocatable]] (with or without a boolean parameter, but in a form that is not dependent on the kindness of subobjects).  At the same time, [[maybe_trivially_relocatable]] looks like it will make some classes, such as `vector`, a bit easier to write — if also a bit more subtle in cases like that _LIBCPP_DEBUG situation.

–Arthur

mihailn...@gmail.com

unread,
Nov 19, 2018, 4:31:03 AM11/19/18
to ISO C++ Standard - Future Proposals
But this is also forces A to behave, doesn't it, which might or might not be the case.
In reality it is not exactly "for its own behavior", right?
 

    struct A { ... };
    template<bool> struct B_relocate_base : public A { int m; B_relocate_base(B_relocate_base&&); ~B_relocate_base(); };
    template<> struct [[trivially_relocatable]] B_relocate_base<true> : public A { int m; B_relocate_base(B_relocate_base&&); ~B_relocate_base(); };
    struct B : public B_relocate_base<std::is_trivially_relocatable_v<A>> {};  // Rule of Zero

Ok, but what about members?

So, if I get this straight we have two options:

struct [[maybe_reloc]] A : Base 
{
  A(A&&); ~A(); 
  B b;
  C c;
  D d;
};

and

struct [[reloc]] A : Base 
{
  A(A&&); ~A(); 
  B b;
  C c;
  D d;
};

In the first case you either are correctly (no UB) relocatable or not. Changing relocatability property of any member and base can turn this on and off.
In the second case we force relocatability, taking responsibility for the class, its members and bases. Changing relocatability property of any member and base can turn into an UB.

Is this the more or less complete picture (minus conditional attr)?


Now, I do understand the need to force reloc, but can we consider making this more fine grained? 

This is, an attr / keyword is used to vouch on a object.

struct [[reloc]] A : Base 
{
  A(A&&); ~A(); 
  B b;
  C c;
  D d;
};

This only vouches for our class alone, literally "for its own behavior" - the move and the dtor of our class do the right thing.
If any member or base is not trivially relocatable it will be a compile time error (or turn reloc off if go with "maybe" semantics).   

Now, if we are sure that some of our members and bases do the right thing, or that we use them in the right way in our context (the batteries vector)
then we vouch for that base or member alone not for the all members and bases.

 
struct [[reloc]] A :  [[reloc]] Base 
{
  A(A&&); ~A(); 
  B b;
  [[reloc]] C c;
  D d;
};

If B and D are trivially relocatable as well we are good to go. If at any point B D become non-trivially reloc, we fail to compile. If C or Base become trivial, nothing changes.

Having this model will allow us to safely force, as we only vouching for things we have control over

consider

template<class B, class C, class D>
struct [[maybe_reloc]] A :  [[reloc]] Base 
{
  A(A&&); ~A(); 
  B b;
  C c;
  D d;
};

We can allow us to force the base as we have written it, or we know it and/or we use it in the correct way.
We have no control over the members. Yet we might want to be relocatable, IFF we can do so.

The above scenario is either not possible under current model, or extremely hard and metaprogrammy.

Arthur O'Dwyer

unread,
Nov 21, 2018, 10:49:58 PM11/21/18
to std-pr...@isocpp.org
For the record, here are my own !votes. Some of my views have evolved since P1144R0.
My original suggestions, recorded with parentheses in P1144R0, were
SF SF SF SF SF
N SA SA A SF
SF SF SF SF N

The !votes I have actually recorded for myself in P1144R1 are
SF SF SF SF SF
A SA SA N F
N F SF SF N

- Having implemented parts of the libc++ patch multiple times with different syntaxes (see the Clang patch discussion for details), I am now more favorably disposed toward the idea of an attribute with a boolean parameter.
- I am less comfortable now with P1144R0's idea that a type could be simultaneously "trivially relocatable" and "not nothrow relocatable." It doesn't present any practical difficulties for library vendors, but it feels weird. I am amenable to the idea of removing the is_relocatable and is_nothrow_relocatable type traits.

–Arthur


On Mon, Nov 12, 2018 at 11:54 AM <floria...@gmail.com> wrote:
Le lundi 12 novembre 2018 02:35:40 UTC+1, Arthur O'Dwyer a écrit :
P1144R0 "Object relocation in terms of move plus destroy" was presented to SG17 (EWGI) in San Diego. (Thanks to Corentin Jabot for trying to make it happen!) The paper lists the following straw polls that could have been taken. None of these polls were taken, and no feedback was given on the paper in San Diego.

So I'd like to get your opinions!  Please reply in this thread with your !votes on any or all of the following statements, in the traditional WG21 straw poll format: "Strongly For" the statement as written; "For" it; "Neutral" (as in, you considered the question and your expert opinion is that you are neutral on it — please do not use this option as a synonym for abstaining due to lack of an opinion); "Against" the statement as written; or "Strongly Against" it.

The polls will remain open for one week, until Sunday 2018-11-18. If you don't want your !votes to be public, you can always email them to me privately.
I will tally the ballots and report the results in P1144R1, which will appear in the post-San-Diego mailing (submission deadline: 2018-11-26).

olee...@gmail.com

unread,
Nov 22, 2018, 5:08:47 AM11/22/18
to ISO C++ Standard - Future Proposals

On Monday, November 19, 2018 at 1:44:17 AM UTC+1, Arthur O'Dwyer wrote:

> * RELOCATE is a bikeshed placeholder for a special member;
> * `default` means that the class is trivially relocatable if all its bases
> and members are trivially relocatable, and otherwise is not (there is no
> way to "force" trivial relocatability);

That I disagree with, though not strongly so.

I now strongly disagree with this, unless somebody can show me how to implement `std::optional<A>` so that it will inherit the trivial relocatability of `A`, without any "forcing."  I have tried and failed with libc++'s optional.
Part of the philosophical problem is that `optional` implements "destructibility" at a completely different level of the inheritance hierarchy than "move-constructibility." So in order to make all of `optional`'s base classes trivially relocatable, we essentially have to lie to the compiler and pretend that e.g. __optional_destructible_base is "trivially relocatable" when in fact it's not.  (In fact, because of the union, it is not even move-constructible! I think that is the practical problem I'm hitting.)  I would strongly prefer to have the most derived class, `optional`, take responsibility for all of its behavior as a package deal, without having to saddle every base class with a [[maybe_trivially_relocatable]] attribute which is actually a lie in most cases.

So, having investigated this [[maybe_trivially_relocatable]] attribute a little bit, I am currently of the opinion that we still need [[trivially_relocatable]] (with or without a boolean parameter, but in a form that is not dependent on the kindness of subobjects).  At the same time, [[maybe_trivially_relocatable]] looks like it will make some classes, such as `vector`, a bit easier to write — if also a bit more subtle in cases like that _LIBCPP_DEBUG situation.

–Arthur
 
I'm concerned that if we can't reach something close to consensus here, the chances won't be much better in the committee.

A standard attribute that forces trivial relocatability regardless of subobjects? That sounds like a non-starter to me. But the standard library doesn't need to limit itself to using standard C++. std::optional could use a compiler specific attribute, or specialize is_trivially_relocatable even if users aren't allowed to do that.

Chris Gunn

unread,
Nov 24, 2018, 2:05:51 AM11/24/18
to ISO C++ Standard - Future Proposals
Out of interest, did you consider the alternative option of adding an entirely new set of special functions?

Unfortunately, the existing r-value reference syntax didn't leave any room for further extensions. But we could create an alternative syntax for r-values references, like this:

void foo(T &rvalue bar);

Then this new syntax could then be extended for move+destroy:

void foo(T &deadvalue bar);

Also, it might be a good idea to allow multiple reference annotations to be specified at the same time, for when the implementation of the r-value reference function and destroy+move function are identical:

void foo(T &rvalue deadvalue bar);

Though, I have somewhat of an ulterior motive for making this suggestion. Specifically, if we were to also add a similar reference annotation for const references, like this:

void foo(T &constvalue bar);

Then we could also do this:

void foo(T &constvalue rvalue bar);

So that we could avoid annoying boilerplate when the const-reference and r-value reference versions of a function can be identical.

That being said, this would be somewhat of a radical departure from existing C++ syntax. And it would require creating new keywords. So I am not sure it is a realistic suggestion. But it was fun to think about. :-)

On Sunday, 11 November 2018 17:35:40 UTC-8, Arthur O'Dwyer wrote:
P1144R0 "Object relocation in terms of move plus destroy" was presented to SG17 (EWGI) in San Diego. (Thanks to Corentin Jabot for trying to make it happen!) The paper lists the following straw polls that could have been taken. None of these polls were taken, and no feedback was given on the paper in San Diego.

So I'd like to get your opinions!  Please reply in this thread with your !votes on any or all of the following statements, in the traditional WG21 straw poll format: "Strongly For" the statement as written; "For" it; "Neutral" (as in, you considered the question and your expert opinion is that you are neutral on it — please do not use this option as a synonym for abstaining due to lack of an opinion); "Against" the statement as written; or "Strongly Against" it.

The polls will remain open for one week, until Sunday 2018-11-18. If you don't want your !votes to be public, you can always email them to me privately.
I will tally the ballots and report the results in P1144R1, which will appear in the post-San-Diego mailing (submission deadline: 2018-11-26).

Here are the polls. Please vote in any or all of them, but only after reading the paper. When a poll says "...as proposed in this paper," it's referring to the formal wording from P1144R0. You would have to read that formal wording to know what's being asked!
---------------------------------------

EWG1. We approve of the general idea that user-defined classes should be able to warrant their own trivial relocatability via a standard mechanism.

EWG2. We approve of the general idea that user-defined classes which follow the Rule of Zero should inherit the trivial relocatability of their bases and members.

EWG3. Nobody should be able to warrant the trivial relocatability of class `C` except for class `C` itself (i.e., we do not want to see a customization point analogous to `std::hash`).

EWG4. A class should be able to warrant its own trivial relocatability via the attribute `[[trivially_relocatable]]`, as proposed in this paper.

EWG5. A class should be able to warrant its own trivial relocatability via some attribute, but not necessarily under that exact name.

EWG6. A class should be able to warrant its own trivial relocatability as proposed in this paper, but we prefer to see a contextual keyword rather than an attribute.

EWG7. If a trait with the semantics of `is_trivially_relocatable<T>` is added to the `<type_traits>` header, the programmer should be permitted to specialize it for program-defined types (i.e., we want to see that trait itself become a customization point analogous to `std::hash`).

EWG8. Trivial relocatability should be assumed by default. Classes such as those in Appendix C should indicate their non-trivial relocatability via an opt-in mechanism.

EWG9. To simplify conditionally trivial relocation, if an attribute with the semantics of `[[trivially_relocatable]]` is added, it should take a boolean argument.

LEWG10. The algorithm `uninitialized_relocate(first, last, d_first)` should be added to the `<memory>` header, as proposed in this paper.

LEWG11. The type trait `is_relocatable<T>` should be added to the `<type_traits>` header, as proposed in this paper.

LEWG12. If `is_relocatable<T>` is added, then we should also add `is_nothrow_relocatable<T>`, as proposed in this paper.

LEWG13. The type trait `is_trivially_relocatable<T>` should be added to the `<type_traits>` header, under that exact name, as proposed in this paper.

LEWG14. We approve of a trait with the semantics of `is_trivially_relocatable<T>`, but possibly under a different name. (For example, `is_bitwise_relocatable`.)

LEWG15. If `is_trivially_relocatable<T>` is added, under that exact name, then the type trait `is_trivially_swappable<T>` should also be added to the `<type_traits>` header.

-----------------------

Discussion and comments on P1144R0 is also welcome — preferably in the original discussion thread, or via private email, but if it winds up in this thread, I'm okay with that.

Thanks,
Arthur

Thiago Macieira

unread,
Nov 24, 2018, 12:32:37 PM11/24/18
to std-pr...@isocpp.org
On Friday, 23 November 2018 23:05:51 PST Chris Gunn wrote:
> Unfortunately, the existing r-value reference syntax didn't leave any room
> for further extensions. But we could create an alternative syntax for
> r-values references, like this:
>
> void foo(T &rvalue bar);
>
> Then this new syntax could then be extended for move+destroy:
>
> void foo(T &deadvalue bar);

Before we talk about syntax, we have to talk about why we would need it. Can
you describe what could be done with this syntax that cannot under what has
been proposed so far, with just traits and attributes?

I think it boils down to the question of whether we need to have a non-trivial
relocate operation that is faster than move + destroy.
Reply all
Reply to author
Forward
0 new messages