Date: Sat, 30 Apr 2022 04:17:59 +0200
Hi,
On 29/04/2022 18:08, Sébastien Bini via Std-Proposals wrote:
> About the last point, here is a quick overview: consider a class that
> guarantees (unique) ownership over some resources (i.e. allocated in
> constructor or otherwise throws, and deallocates in destructor). Basic
> examples are a non-null pointer class or a socket wrapper class. In a
> pure class design perspective:
>
> * those classes shouldn't be copied as they provide unique access to
> the resource.
> * they could be movable but that's not ideal. The move constructor may
> leave them in a dirty state or else rely on complicated mechanisms
> not to do so. The move constructor for such classes:
> o either breaks the class guarantee. That is the case if the
> resource is moved from one instance to the other, leaving the
> original instance with an invalid resource. As stated this
> breaks our class invariant, which is to always offer unique
> access to some resource.
> o either needlessly complicates class design to work around the
> naive implementation described above. This may include
> allocating new unique resources to the moved instance in the
> move constructor, or to do it lazily at a later stage the next
> time the moved instance is reused.
> o may not be appropriate. What would you do with a moved-from
> socket wrapper instance? You don't know whether it owns any
> socket, and if it does, it will probably be on something you
> don't want. Most of the time, C++ programmers just discard
> moved-from instances anyway as they are unsure of what they contain.
> * it is a legitimate need to be able to "move" them around.
> * the relocation constructor fits this need: the classes can be
> relocated to another location. As the relocated instance is
> guaranteed never to be touched again, the relocation constructor can
> leave the relocated instance in a dirty invalid state (which the
> move constructor cannot).
I'm probably missing something, but from what you say above and from the
TempDir example on page 7, all of this sounds like existing move
semantics with the additional enforcement that a moved-from object isn't
ever touched again (not even reassigned / reset).
(From a syntax point of view, I'm not sure how that is desirable, as one
could no longer something like `other = reloc obj; delete &obj;`, but I
don't think it's a particularly compelling use case...)
Anyways, a justification for relocation over move semantics on page 3
says that "the move constructor performs extra operations to ensure that
the moved-from object remains at a valid state." This is not universally
true. It is true for the Standard Library (and makes certain std::list
implementations of move operations expensive / noexcept(false)); that's
just stdlib's stance. A class author can always state that a moved-from
object of their class is only partially formed. In this last case, I am
not sure the paper convincly justifies operator reloc over the status
quo (which includes clang-tidy "use after move" checks and so on).
My 2 c,
On 29/04/2022 18:08, Sébastien Bini via Std-Proposals wrote:
> About the last point, here is a quick overview: consider a class that
> guarantees (unique) ownership over some resources (i.e. allocated in
> constructor or otherwise throws, and deallocates in destructor). Basic
> examples are a non-null pointer class or a socket wrapper class. In a
> pure class design perspective:
>
> * those classes shouldn't be copied as they provide unique access to
> the resource.
> * they could be movable but that's not ideal. The move constructor may
> leave them in a dirty state or else rely on complicated mechanisms
> not to do so. The move constructor for such classes:
> o either breaks the class guarantee. That is the case if the
> resource is moved from one instance to the other, leaving the
> original instance with an invalid resource. As stated this
> breaks our class invariant, which is to always offer unique
> access to some resource.
> o either needlessly complicates class design to work around the
> naive implementation described above. This may include
> allocating new unique resources to the moved instance in the
> move constructor, or to do it lazily at a later stage the next
> time the moved instance is reused.
> o may not be appropriate. What would you do with a moved-from
> socket wrapper instance? You don't know whether it owns any
> socket, and if it does, it will probably be on something you
> don't want. Most of the time, C++ programmers just discard
> moved-from instances anyway as they are unsure of what they contain.
> * it is a legitimate need to be able to "move" them around.
> * the relocation constructor fits this need: the classes can be
> relocated to another location. As the relocated instance is
> guaranteed never to be touched again, the relocation constructor can
> leave the relocated instance in a dirty invalid state (which the
> move constructor cannot).
I'm probably missing something, but from what you say above and from the
TempDir example on page 7, all of this sounds like existing move
semantics with the additional enforcement that a moved-from object isn't
ever touched again (not even reassigned / reset).
(From a syntax point of view, I'm not sure how that is desirable, as one
could no longer something like `other = reloc obj; delete &obj;`, but I
don't think it's a particularly compelling use case...)
Anyways, a justification for relocation over move semantics on page 3
says that "the move constructor performs extra operations to ensure that
the moved-from object remains at a valid state." This is not universally
true. It is true for the Standard Library (and makes certain std::list
implementations of move operations expensive / noexcept(false)); that's
just stdlib's stance. A class author can always state that a moved-from
object of their class is only partially formed. In this last case, I am
not sure the paper convincly justifies operator reloc over the status
quo (which includes clang-tidy "use after move" checks and so on).
My 2 c,
-- Giuseppe D'Angelo
Received on 2022-04-30 02:18:03