Why are the swap member functions in STL containers not declared noexcept?

♀尐吖头ヾ 提交于 2019-12-22 02:04:50

问题


As of N3797 the C++ standard requires swap functions of containers to not throw any exceptions unless specified otherwise [container.requirements.general] (23.2.1§10).

  • Why are the swap member functions that are specified to not throw not declared noexcept?

The same question applies to the specialized non-member swap overloads.


回答1:


Further to what refp said, here's a post from Daniel Krügler on the std-discussion mailing list:

The internal policy to declare a function as unconditional noexcept is explained in

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3279.pdf

With the terminology used in that paper, std::vector's swap function has a narrowing contract, that is it has preconditions in regard to the allocators of the participating objects. This means, there exists the possibility that callers may violate the preconditions and an implementation should be allowed to signal this my different means than by termination. Therefore such functions should not be noexcept, but it should have an effective element "Throws: Nothing" because this applies to the situation when the preconditions are satisfied.

(link)

Said internal policy is the canonical, official answer to your question.




回答2:


It may sound odd at first, but not explicitly stating that swap of standard container is noexcept is intentional; and it all boils down to undefined behavior (UB).


23.2.1p9 General Container Requirements [container.requirements.general]

The expression a.swap(b), for containers a and b of a standard container type other than array, shall exchange the values of a and bwithout invoking any move, copy, or swap operations on the individual container elements.

Any Compare, Pred, or Hash objects beloning to a and b shall be swappable and shall be exchanged by unqualified calls to non-member swap.

If allocator_traits<allocator_type>::propagate_on_container_swap::value is true, then the allocators of a and b shall also be exchanged using an unqalified call to non-member swap. Otherwise, they shall not be swapped, and the behavior is undefined unless `a.get_allocator () == b.get_allocator ().

Note: italics added by me.


Why is the previous section relevant to my question?

Since the swap of standard containers has a precondition (most importantly the last paragraph of the previously quoted section of the Standard), that may lead to UB if not satisfied, the Standard doesn't want to impose "impossible" constraints on implementations.


The Standard says the following about undefined behaviour:

1.3.24 undefined behavior [defns.undefined]

Behavior for which this International Standard imposes no requirements.


Only criminals, and perhaps salesmen, would consider a No to be something other than a No, but when the Standard says "no requirements" it really means "no requirements"; marking the relevant swap functions as noexcept would impose a requirement on implementations, where there should be none.


Why doesn't the Standard want to impose such requirements?

There's an interesting paper (N3248) on this matter by Alisdair Meredith and John Lakos titled "noexcept prevents Library Validation".

In short it talks about how noexcept will prevent library implementation to use asserts in library code (ie. implementations of the standard library), even during debug mode, and the implications of that.

If C++ had a standardized "testing" vs "production" mode (as the paper calls it), where noexcept would conditionally apply, this would be far less problematic.. but as it currently stands; C++ has no "modes".



来源:https://stackoverflow.com/questions/23754223/why-are-the-swap-member-functions-in-stl-containers-not-declared-noexcept

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!