Why does `polymorphic_allocator` take a `memory_resource` pointer and not a reference?
Asked Answered
P

1

12

The C++17 Standard says:

[mem.poly.allocator.ctor]

polymorphic_allocator(memory_resource* r);
  • Requires: r is non-null.

  • Effects: Sets memory_­rsrc to r.

  • Throws: Nothing.

  • [ Note: This constructor provides an implicit conversion from memory_­resource*. — end note ]

What's the point of accepting a memory_resource* instead of a memory_resource& if the "requires" clause mentions that r must be non-null?

The Bloomberg¹ style guide encourages accepting arguments that are going to be mutated by pointer instead of reference so that the ampersand on the caller side becomes a visual marker for mutation. However, there is no such precedent in the Standard.

What is the reason that r is taken as a pointer and not as a reference?


¹ pmr was standardized with heavy Bloomberg participation, as the company uses a polymorphic allocator model.

Petie answered 6/5, 2019 at 23:12 Comment(4)
I think your note might indicate the reason. The design was heavily influenced by Bloomberg, but I can't personally say whether this aspect was contested in a meeting.Ashaashamed
A guess: consistency with [io]streams that take streambuf pointer. These are the only other entities in std I can think of that are a similar kind of non-owning interface adapter.Deconsecrate
@chris: I just found it weird that this was not contested, as it would simplify the wording... and the committee likes wording to be as simple as possible :)Petie
I suspect Effects: Sets memory_­rsrc to r. might be the relevant clause. By taking the argument by-pointer rather than by-reference, the API encourages the programmer to think more carefully about object-lifetime issues regarding the passed-in object. In particular, when calling a function/method that takes an argument by-reference, programmers who didn't read the documentation carefully (read: most of us ;) ) would likely not expect that function to retain a pointer to the passed-in object for later use after the call has returned.Croy
J
10

N3916:

Note that the memory-resource library is designed so that the ShoppingList constructor accepts a pointer to a memory_resource rather than a reference to a memory_resource. It was noted that one common practice is to use references rather than pointers in situations where a null pointer is out of contract. However, there is a more compelling practice of avoiding constructors that take objects by reference and store their addresses. We also want to avoid passing non-const references, as that, too, is usually considered bad practice (except in overloaded operators).

Jolin answered 7/5, 2019 at 10:20 Comment(1)
I really don't understand why the second practice is preferred. I would understand why they have chosen pointer instead of reference, if it were defined what exactly to do when NULL pointer is passed. E.g. use get_default_resource as boost does, but it's a non-standard extension. But in this case they introduced a possibility for undefined behavior when NULL pointer is passed just because they wanted to fulfill some good practice. For me it's nonsense. Now a user must read the documentation and understand that NULL is simply not allowed, or he will just get undefined behavior.Muliebrity

© 2022 - 2024 — McMap. All rights reserved.