Date: Mon, 16 Dec 2024 10:24:31 -0800
If the object is in an invalid state, how do you know that it is even
destructible?
On Mon, Dec 16, 2024 at 10:15 AM Paul Meckel via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Hi.
>
> I propose that the requirements of "moved-from" objects belonging to the
> standard library are relaxed from "unspecified but valid" to
> "unspecified, and potentially invalid" with "the use of their state
> results in undefined behavior".
>
> My reasoning for this proposal is this:
>
> Moving from an object occurs in two scenarios only:
>
> 1. Moving from a temporary, in which case this doesn't apply
> 2. Moving explicitly, for example with std::move
>
> In both cases, the programmer indicates that the moved-from object is no
> longer important to them, and that it's resources may be used. As such
> the only two valid operations on these objects should be the same two
> valid operations as on uninitialized variables, as they are conceptually
> the same: assignment and destruction. Anything else makes no sense, and
> there is no use case.
>
> The problem is that the c++ standard places requirements on these moved
> from objects if they are types of the standard library. For example
> std::vector must be in an "unspecified but valid state", where valid
> means that invariants must hold for the moved from object. This in turn
> means that all operations on that object have to be safe. .size() or
> .push_back() need to perform as expected, even though using these
> operations on a moved from object is nonsense.
>
> This places a burden on the library implementers to ensure invariants
> are not violated, and more importantly it violates the core principle of
> c++ as a language: uncompromising performance, even at the cost of
> safety. This is why uninitialized primitive type variables exist, even
> though initializing them to a default value would prevent a lot of bugs.
> c++ is about performance first, and any safety on top of that is
> optional and at no cost if not used. This is why we have both operator[]
> and member function .at() for std::array.
>
> Inherently, querying the state of, or using the value of a moved from
> object is semantically meaningless, as you just declared that you don't
> care about it anymore. A case could be made to allow some member
> functions, such as .clear() for vector, to remain valid even for moved
> from objects as it effectively resets the state; but a more semantically
> correct way would be reassignment of a new vector entirely.
>
> Therefore moving from an object and leaving it in an invalid state, if
> that saves performance, seems like a reasonable decision. Assigning 0 to
> the size member of a vector adds only one extra instruction per move
> (but so does default initializing primitive types, and that was deemed
> too much also), but for std::list, this means a dynamic memory
> allocation for a new sentinel node, which in turn may throw, which is
> why the move operations for std::list are not noexcept, even though move
> operations should be noexcept. So you did all that work, even
> reallocating memory, on an object that you know that the programmer
> intends to discard or reassign over. It makes no sense to perform that
> work.
>
> Impact on existing code:
>
> Code using moved-from object's state, such as relying on a vector being
> empty after a move is already a logic error, and a bug, as the state of
> the vector may not be empty. It is unspecified after all, even if in
> practice it very often is empty.
>
> Standard libraries do not need to implement these changes immediately,
> as the current safe behavior is also valid for undefined behavior.
>
> Correctly written code without the implicit logic error that comes with
> using a moved-from object's state remain valid. Exceptions are those
> which use a reset like function, such as .clear() for container types,
> instead of a reassignment.
>
>
> What do you think?
>
> Best Regards
>
> Paul
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
destructible?
On Mon, Dec 16, 2024 at 10:15 AM Paul Meckel via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> Hi.
>
> I propose that the requirements of "moved-from" objects belonging to the
> standard library are relaxed from "unspecified but valid" to
> "unspecified, and potentially invalid" with "the use of their state
> results in undefined behavior".
>
> My reasoning for this proposal is this:
>
> Moving from an object occurs in two scenarios only:
>
> 1. Moving from a temporary, in which case this doesn't apply
> 2. Moving explicitly, for example with std::move
>
> In both cases, the programmer indicates that the moved-from object is no
> longer important to them, and that it's resources may be used. As such
> the only two valid operations on these objects should be the same two
> valid operations as on uninitialized variables, as they are conceptually
> the same: assignment and destruction. Anything else makes no sense, and
> there is no use case.
>
> The problem is that the c++ standard places requirements on these moved
> from objects if they are types of the standard library. For example
> std::vector must be in an "unspecified but valid state", where valid
> means that invariants must hold for the moved from object. This in turn
> means that all operations on that object have to be safe. .size() or
> .push_back() need to perform as expected, even though using these
> operations on a moved from object is nonsense.
>
> This places a burden on the library implementers to ensure invariants
> are not violated, and more importantly it violates the core principle of
> c++ as a language: uncompromising performance, even at the cost of
> safety. This is why uninitialized primitive type variables exist, even
> though initializing them to a default value would prevent a lot of bugs.
> c++ is about performance first, and any safety on top of that is
> optional and at no cost if not used. This is why we have both operator[]
> and member function .at() for std::array.
>
> Inherently, querying the state of, or using the value of a moved from
> object is semantically meaningless, as you just declared that you don't
> care about it anymore. A case could be made to allow some member
> functions, such as .clear() for vector, to remain valid even for moved
> from objects as it effectively resets the state; but a more semantically
> correct way would be reassignment of a new vector entirely.
>
> Therefore moving from an object and leaving it in an invalid state, if
> that saves performance, seems like a reasonable decision. Assigning 0 to
> the size member of a vector adds only one extra instruction per move
> (but so does default initializing primitive types, and that was deemed
> too much also), but for std::list, this means a dynamic memory
> allocation for a new sentinel node, which in turn may throw, which is
> why the move operations for std::list are not noexcept, even though move
> operations should be noexcept. So you did all that work, even
> reallocating memory, on an object that you know that the programmer
> intends to discard or reassign over. It makes no sense to perform that
> work.
>
> Impact on existing code:
>
> Code using moved-from object's state, such as relying on a vector being
> empty after a move is already a logic error, and a bug, as the state of
> the vector may not be empty. It is unspecified after all, even if in
> practice it very often is empty.
>
> Standard libraries do not need to implement these changes immediately,
> as the current safe behavior is also valid for undefined behavior.
>
> Correctly written code without the implicit logic error that comes with
> using a moved-from object's state remain valid. Exceptions are those
> which use a reset like function, such as .clear() for container types,
> instead of a reassignment.
>
>
> What do you think?
>
> Best Regards
>
> Paul
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2024-12-16 18:24:48