This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

3120. Unclear behavior of monotonic_buffer_resource::release()

Section: 20.12.6.3 [mem.res.monotonic.buffer.mem] Status: WP Submitter: Arthur O'Dwyer Opened: 2018-06-10 Last modified: 2020-11-09

Priority: 2

View all other issues in [mem.res.monotonic.buffer.mem].

View all issues with WP status.

Discussion:

The effects of monotonic_buffer_resource::release() are defined as:

Calls upstream_rsrc->deallocate() as necessary to release all allocated memory.

This doesn't give any instruction on what to do with the memory controlled by the monotonic_buffer_resource which was not allocated, i.e., what to do with the initial buffer provided to its constructor.

Boost.Container's pmr implementation expels its initial buffer after a release(). Arthur O'Dwyer's proposed pmr implementation for libc++ reuses the initial buffer after a release(), on the assumption that this is what the average library user will be expecting.

#include <memory_resource>

int main() 
{
  char buffer[100];
  {
    std::pmr::monotonic_buffer_resource mr(buffer, 100, std::pmr::null_memory_resource());
    mr.release();
    mr.allocate(60);  // A
  }
  {
    std::pmr::monotonic_buffer_resource mr(buffer, 100, std::pmr::null_memory_resource());
    mr.allocate(60);  // B
    mr.release();
    mr.allocate(60);  // C
  }
}

Assume that allocation "B" always succeeds.
With the proposed libc++ implementation, allocations "A" and "C" both succeed.
With Boost.Container's implementation, allocations "A" and "C" both fail.
Using another plausible implementation strategy, allocation "A" could succeed but allocation "C" could fail. I have been informed that MSVC's implementation does this.

Which of these strategies should be permitted by the Standard?

Arthur considers "A and C both succeed" to be the obviously most user-friendly strategy, and really really hopes it's going to be permitted. Requiring "C" to succeed is unnecessary (and would render MSVC's current implementation non-conforming) but could help programmers concerned with portability between different implementations.

Another side-effect of release() which goes underspecified by the Standard is the effect of release() on next_buffer_size. As currently written, my interpretation is that release() is not permitted to decrease current_buffer_size; I'm not sure if this is a feature or a bug.

Consider this test case (taken from here):

std::pmr::monotonic_buffer_resource mr(std::pmr::new_delete_resource());
for (int i=0; i < 100; ++i) {
  mr.allocate(1);  // D
  mr.release();
}

Arthur believes it is important that the 100th invocation of line "D" does not attempt to allocate 2100 bytes from the upstream resource.

[2018-06-23 after reflector discussion]

Priority set to 2

Previous resolution [SUPERSEDED]:

This wording is relative to N4750.

[Drafting note: The resolution depicted below would make MSVC's and my-proposed-libc++'s implementations both conforming.]

  1. Modify 20.12.6.3 [mem.res.monotonic.buffer.mem] as indicated:

    void release();
    

    -1- Effects: Calls upstream_rsrc->deallocate() as necessary to release all allocated memory. Resets the state of the initial buffer.

    -2- [Note: The memory is released back to upstream_rsrc even if some blocks that were allocated from this have not been deallocated from this. This function has an unspecified effect on next_buffer_size.end note]

[2018-08-23 Batavia Issues processing]

We liked Pablo's wording from the reflector discussion. Status to Open.

Previous resolution [SUPERSEDED]:

This wording is relative to N4750.

  1. Modify 20.12.6.3 [mem.res.monotonic.buffer.mem] as indicated:

    void release();
    

    -1- Effects: Calls upstream_rsrc->deallocate() as necessary to release all allocated memory. Resets *this to its initial state at construction.

[2020-10-03; Daniel comments and provides improved wording]

The recent wording introduces the very generic term "state" without giving a concrete definition of that term. During reflector discussions different interpretations of that term were expressed. The revised wording below gets rid of that word and replaces it by the actually involved exposition-only members.

[2020-10-06; moved to Tentatively Ready after seven votes in favour in reflector poll]

[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4861.

  1. Modify 20.12.6.3 [mem.res.monotonic.buffer.mem] as indicated:

    void release();
    

    -1- Effects: Calls upstream_rsrc->deallocate() as necessary to release all allocated memory. Resets current_buffer and next_buffer_size to their initial values at construction.