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

3029. pop_heap over-constrains input

Section: 27.8.8.3 [pop.heap] Status: Open Submitter: Mathias Stearn Opened: 2017-11-04 Last modified: 2020-09-06

Priority: 3

View all issues with Open status.

Discussion:

The spec for <algorithms> pop_heap includes

-1- Requires: The range [first, last) shall be a valid non-empty heap.

This has the unfortunate consequence that to pop a value and push a new value is substantially less efficient than necessary. The popped value must be extracted by pop_heap (using up to 2 log N compares and swaps), and then, in push_heap, the new value must be inserted (for up to N compares and swaps, but more usually something like log N).

Simply relaxing the requirement to

-1- Requires: The range [first, last - 1) shall be a valid heap.

enables use of pop_heap in an integrated push-and-pop operation, with less than half the number of expected compare and swap operations. Furthermore, if, as is often the case, the newly pushed value would have ended up at position first, the push/pop operation could complete in time 𝒪(1), instead of (3 log N).

The effect of the proposed relaxation on existing library implementations would be minimal in the extreme, and on existing user code nil. The base algorithm code remains exactly identical. The only changes needed would be to any instrumentation in a debugging version of the library, which would just need to relax its check, and to test suites that should exercise the newly tolerated input.

Users today are tempted to get the improved performance by relying on existing implementations' tacit tolerance of input that only satisfies the proposed, relaxed requirements. In fact, the cppreference.com page on pop_heap offers no hint that this usage is not already allowed. This change would bless such reliance as formally permitted.

After this change, minor extensions to std::priority_queue would enable it to take advantage of the newly efficient operation, perhaps:

void pop_push(const Type&);
void pop_push(Type&&);
template <class... Args> void pop_emplace(Args&&... args);

These will appear in a formal proposal if the resolution is accepted.

[2017-11 Albuquerque Wednesday night issues processing]

Priority set to 3

[2017-11 Albuquerque Saturday issues processing]

status to Open; Marshall to review

Proposed resolution:

This wording is relative to N4700.

  1. Change 27.8.8.3 [pop.heap] as indicated:

    template<class RandomAccessIterator>
      void pop_heap(RandomAccessIterator first, RandomAccessIterator last);
    template<class RandomAccessIterator, class Compare>
      void pop_heap(RandomAccessIterator first, RandomAccessIterator last,
                    Compare comp);
    

    -1- Requires: The range [first, last - 1) shall be a valid non-empty heap. RandomAccessIterator shall satisfy the requirements of ValueSwappable (16.4.4.3 [swappable.requirements]). The type of *first shall satisfy the requirements of MoveConstructible (Table 23) and of MoveAssignable (Table 25).