2198. max_load_factor(z) makes no strong guarantees, but bans useful behavior

Section: 23.2.8 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-10-09 Last modified: 2016-12-10

Priority: 3

View other active issues in [unord.req].

View all other issues in [unord.req].

View all issues with Open status.

Discussion:

The user cannot specify a max_load_factor for their unordered container at construction, it must be supplied after the event, when the container is potentially not empty. The contract for this method is deliberately vague, not guaranteeing to use the value supplied by the user, and any value actually used will be used as a ceiling that the container will attempt to respect.

The only guarantee we have is that, if user requests a max_load_factor that is less than the current load_factor, then the operation will take constant time, thus outlawing an implementation that chooses to rehash and so preserve as a class invariant that load_factor < max_load_factor.

Reasonable options conforming to the standard include ignoring the user's request if the requested value is too low, or deferring the rehash to the next insert operation and allowing the container to have a strange state (wrt max_load_factor) until then - and there is still the question of rehashing if the next insert is for a duplicate key in a unique container.

Given the deliberate vagueness of the current wording, to support a range of reasonable (but not perfect) behaviors, it is not clear why the equally reasonable rehash to restore the constraint should be outlawed. It is not thought that this is a performance critical operation, where users will be repeatedly setting low load factors on populated containers, in a tight or (less unlikely) an instant response scenario.

[2013-03-15 Issues Teleconference]

Moved to Open.

Alisdair to provide wording.

[2016-11-12, Issaquah]

Sat PM: Howard to provide wording

[2016-11-17 Howard provided wording.]

The provided wording is consistent with LWG discussion in Issaquah. An implementation of the proposed wording would be setting max_load_factor() to max(z, load_factor()). This preserves the container invariant:

load_factor() <= max_load_factor()

And it preserves the existing behavior that no rehash is done by this operation.

If it is desired to change the max_load_factor() to something smaller than the current load_factor() that can be done by first reducing the current load_factor() by either increasing bucket_count() (via rehash or reserve), or decreasing size() (e.g. erase), and then changing max_load_factor().

This resolution reaffirms that load_factor() <= max_load_factor() is a container invariant which can never be violated.

[2016-11-27, Nico comments]

Current implementations behave differently.

In regard to the sentence

"The only guarantee we have is that, if user requests a max_load_factor that is less than the current load_factor, then the operation will take constant time, thus outlawing an implementation that chooses to rehash and so preserve as a class invariant that load_factor < max_load_factor."
Note that the current spec says that there is constant complexity without any precondition. So, rehashing to keep the invariant would violate the spec (which is probably not be the intention).

This issue is related to LWG 2199.

Proposed resolution:

Modify Table 87 as follows:

Table 87 — Unordered associative container requirements
Expression Return type Assertion/note pre-/post-condition Complexity
a.max_load_factor(z) void

Pre: z shall be positive. May change the container's maximum load factor, uing z as a hint.

Post: a.load_factor() <= a.max_load_factor()

Note: a.load_factor() is not modified by this operation.

Constant