C++ Logo

std-discussion

Advanced search

Re: Potential defect in the behaviour of the rvalue constructors for std::tuple and std::pair.

From: Barry Revzin <barry.revzin_at_[hidden]>
Date: Sat, 11 Nov 2023 08:12:22 -1000
On Fri, Nov 10, 2023 at 1:53 PM Jason McKesson via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> On Fri, Nov 10, 2023 at 6:20 PM Ville Voutilainen via Std-Discussion
> <std-discussion_at_[hidden]> wrote:
> >
> > On Sat, 11 Nov 2023 at 01:01, Bryan Wong via Std-Discussion
> > <std-discussion_at_[hidden]> wrote:
> > >
> > > Hi all,
> > >
> > > I think I've identified a potential defect in the rvalue constructors
> for `std::tuple` covered under `22.4.4.1 tuple.cnstr p.20-23` on the latest
> draft and wanted to ask about it before making a formal report (may also
> need guidance here if possible, as I've never done it before). I'm also not
> sure if this issue has been raised before.
> > >
> > > When using the tuple rvalue constructors, unexpected behaviour occurs
> with non-movable but copyable types, e.g.
> > >
> > > struct foo {
> > > foo() = default;
> > > foo(foo const&) = default;
> > > foo& operator=(foo const&) = default;
> > > foo(foo&&) = delete;
> > > foo& operator=(foo&&) = delete;
> > > };
> >
> > That type is an abomination. If you can copy a type, you can also move
> > it, and that just then does the same thing as copy if it can't move.
> > The standard library doesn't support types that are copyable but for
> > which move operations are ill-formed. Such types make
> > no sense, and appear only ever in testsuites.
>
> And GSL::not_null, which is something that people widely encourage the use
> of.
>

gsl::not_null<T> is definitely both movable and copyable, there's no reason
for it not to be? Moving just copies it, preserving the non-null-ness - it
doesn't zero out the source. It defaults the copy constructor/assignment
and doesn't declare move.

https://github.com/microsoft/GSL/blob/main/include/gsl/pointers#L118
https://godbolt.org/z/MaGT8Gv9K


>
> Broadly speaking, I agree with you about such types, but they do have
> extremely corner-case uses (`not_null` for example should only ever be
> used as a function parameter).
>
> The core problem is that copyable-but-not-moveable types were never
> intended to be a thing, so if you use such a type as a subobject, the
> standard generates very odd code for them. This isn't just about
> `tuple`; making such a type a member of anything generates nonsense
> code. That is:
>
> ```
> struct container
> {
> gsl::not_null<T*> nn;
> };
> ```
>
> While `not_null` is not considered move-constructible, `container`
> *is*, unless you explicitly =delete the move constructor. That's just
> C++'s default behavior in this case.
>
> Link: https://gcc.godbolt.org/z/z3hbEhbY4
>
> Yes, types like `tuple` *could* override the default behavior, but to
> be honest, it would be kind of weird for a C++ standard library
> aggregate type to behave so differently from a C++ language aggregate
> type. `tuple<not_null>` should behave the same as `container`.
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>

Received on 2023-11-11 18:12:36