Skip to content

Bad subclause nesting in [smartptr] #4881

@jwakely

Description

@jwakely

As a result of #1814 (resolving #252) C++20 and recent drafts have this hierarchy:

  • 20.11 Smart pointers [smartptr]
    • 20.11.1 Class template unique_­ptr [unique.ptr]
      • 20.11.1.1 General [unique.ptr.general]
      • 20.11.1.2 Default deleters [unique.ptr.dltr]
      • 20.11.1.3 unique_­ptr for single objects [unique.ptr.single]
      • 20.11.1.4 unique_­ptr for array objects with a runtime length [unique.ptr.runtime]
      • 20.11.1.5 Creation [unique.ptr.create]
      • 20.11.1.6 Specialized algorithms [unique.ptr.special]
      • 20.11.1.7 I/O [unique.ptr.io]
    • 20.11.2 Class bad_­weak_­ptr [util.smartptr.weak.bad]
    • 20.11.3 Class template shared_­ptr [util.smartptr.shared]
    • 20.11.4 Class template weak_­ptr [util.smartptr.weak]
    • 20.11.5 Class template owner_­less [util.smartptr.ownerless]
    • 20.11.6 Class template enable_­shared_­from_­this [util.smartptr.enab]
    • 20.11.7 Smart pointer hash support [util.smartptr.hash]
    • 20.11.8 Class template out_­ptr_­t [out.ptr.t]
    • 20.11.9 Function template out_­ptr [out.ptr]
    • 20.11.10 Class template inout_­ptr_­t [inout.ptr.t]
    • 20.11.11 Function template inout_­ptr [inout.ptr]

Why is everything related to unique_ptr (i.e. default_delete and unique_ptr and unique_ptr<T[]> and make_unique and swap and relational operators and stream insertion) all grouped under 20.11.1, but then every component related to shared_ptr gets its own subclause at the same level?

And why is default_delete defined under a subclause called "Class template unique_ptr" when it's not part of that class template? Shouldn't "Class template unique_ptr" just define, y'know, the class template unique_ptr?

Could we either restore [util.sharedptr] and put all the shared_ptr stuff back under there, and maybe add a new parent subclause for the in/out pointer utilities, or could we consistently apply #1814 and also dissolve [unique.ptr] and move its children up a level? The current grouping is just terrible. I suggested an alternative solution at #252 (comment) and I still think that would have been much better than turning the whole [smartptr] subclause into a mess just to fix a small problem with hash<unique_ptr<T,D>>.

i.e. either four subclauses under [smartptr] (and change the title of [unique.ptr]):

  • 20.11 Smart pointers [smartptr]
    • 20.11.1 Unique-ownership pointers [unique.ptr]
      • 20.11.1.1 General [unique.ptr.general]
      • 20.11.1.2 Default deleters [unique.ptr.dltr]
      • 20.11.1.3 unique_­ptr for single objects [unique.ptr.single]
      • 20.11.1.4 unique_­ptr for array objects with a runtime length [unique.ptr.runtime]
      • 20.11.1.5 Creation [unique.ptr.create]
      • 20.11.1.6 Specialized algorithms [unique.ptr.special]
      • 20.11.1.7 I/O [unique.ptr.io]
    • 20.11.2 Shared-ownership pointers [util.sharedptr]
      • 20.11.2.1 Class bad_­weak_­ptr [util.smartptr.weak.bad]
      • 20.11.2.2 Class template shared_­ptr [util.smartptr.shared]
      • 20.11.2.3 Class template weak_­ptr [util.smartptr.weak]
      • 20.11.2.4 Class template owner_­less [util.smartptr.ownerless]
      • 20.11.2.5 Class template enable_­shared_­from_­this [util.smartptr.enab]
    • 20.11.3 Smart pointer hash support [util.smartptr.hash]
    • 20.11.4 Smart pointer adaptors [smartptr.adapt]
      • 20.11.4.1 Class template out_­ptr_­t [out.ptr.t]
      • 20.11.4.2 Function template out_­ptr [out.ptr]
      • 20.11.4.3 Class template inout_­ptr_­t [inout.ptr.t]
      • 20.11.4.4 Function template inout_­ptr [inout.ptr]

Or dissolve [unique.ptr] and move its children up:

  • 20.11 Smart pointers [smartptr]
    • 20.11.1 Unique-ownership pointers [unique.ptr.general]
    • 20.11.2 Default deleters [unique.ptr.dltr]
    • 20.11.3 unique_­ptr for single objects [unique.ptr.single]
    • 20.11.4 unique_­ptr for array objects with a runtime length [unique.ptr.runtime]
    • 20.11.5 Creation [unique.ptr.create]
    • 20.11.6 Specialized algorithms [unique.ptr.special]
    • 20.11.7 I/O [unique.ptr.io]
    • 20.11.8 Class bad_­weak_­ptr [util.smartptr.weak.bad]
    • 20.11.9 Class template shared_­ptr [util.smartptr.shared]
    • 20.11.10 Class template weak_­ptr [util.smartptr.weak]
    • ...

The first alternative seems obviously better to me. There's no good reason to have an entirely flat hierarchy for every subclause under [smartptr] when there are three clear sets of different things there.

I still think moving hash<unique_ptr<T,D>> adjacent to unique_ptr and keeping hash<shared_ptr<T>> adjacent to shared_ptr makes more sense than having a separate subclause just for the two hash specializations. Why do swap and relational ops and I/O get placed adjacent to the class templates, but not hash? Should we also group hash<any> and hash<optional<T>> and hash<variant<T...>> together, instead of where they are now? (No, we should not!)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions