ISO/ IEC JTC1/SC22/WG21 N0809

Supplemental Issues List for Library
P.J. Plauger
2 November 1995
-------- Clause 17 Issues -------
Table 22 has dropped the header <ciso646> without approval.
Editorial change (without approval) now makes normative the
various #includes in header synopses. This is a dangerous
overspecification -- the ODR makes clear when one header must
include another. Any attempt to list all dependencies is sure
to introduce many errors, both of commission and omission.
-------- Clause 21 Issues -------
The copy constructor for a basic_string always replaces its
allocator with a default allocator. This is surprising behavior.
(Same is true of all containers in clause 23.) Should supply a
copy constructor that truly copies, then remove default allocator
argument from current constructor to disambiguate.
-------- Clause 22 Issues -------
Table 55 is still missing codecvt<char, char, mbstate_t>, as
well as the four international versions of money_get/put noted
in the box that follows.
locale() description says that a call to either the C function
setlocale or the C++ function locale::global() alters the behavior
of this constructor. Such a nasty coupling from C to C++ should
be avoided. Better to say that only locale::global() affects
locale(), since that function calls setlocale() anyway -- and
it can establish global locales you can't even describe in C.
Having the C library subtly affect the C++ library is neither
necessary nor desirable. (On the other hand, it wouldn't hurt
to say *somewhere* in clause 22 that all those locale names
have the same effect *as if* they were used in a setlocale call
and affected specific parallel behavior in the C library. Right
now, the behavior of much of clause 22 is left to the imagination.)
locale::global() should be the only mechanism for altering the
C++ global locale, as described above for
use_facet still has murky semantics. Nathan's intent, communicated
to me privately, is that calling use_facet should have behavior
that even he admits is surprising. If the named locale doesn't
contain the requested facet, the global locale is inspected.
If the global locale contains the facet, that is what is returned;
otherwise, the function throws an exception. So far, so good.
But the cryptic use of the term immutable is meant to suggest
that such a facet is then *copied into the first locale inspected.*
Thus, a partially transparent locale slowly grows more opaque.
Just when it inherits facets from the current underlying global
locale depends heavily on the pattern of calls to use_facet --
hardly predictable behavior.
Tom Plum and I have argued repeatedly that the locale machinery
should *permit* (but not require) the use of transparent and/or
semi-transparent locales in iostreams objects. Indeed, the only
way to reproduce EXISTING PRACTICE is to permit the imbuing of
transparent locales in iostreams objects. Nathan's stated intent
is to ensure that this optional behavior is *not* permitted,
in a portable C++ program. He has made the use of transparent
locales undefined behavior in several important contexts, and he
has at least tried to mandate caching, which interferes with their
use. We believe that locales can, should, and must be usable in
several styles of programming.
In private conversations, Nathan has told me that his strong
opposition to the flexibility I keep asking for stems from a
concern about efficiency in multithreading environments. He wants
assurance that a facet delivered by use_facet will not evaporate
if a separate thread changes the global locale object. (He doesn't
seem to worry about the per-stream object being changed, for some
reason.) Caching the facet in the per-stream object thus serves
as a kind of local lock on the facet, avoiding the need to lock
out thread switching while the facet is in use. (I think I've
fleshed out his brief statements correctly.)
But there are all sorts of ways to solve this problem, in a library
extended for multithread support, without mucking up the semantics
of locales for everyone. I've developed an alternate form of
use_locale that returns a smart reference to the facet. When the
smart reference evaporates, the usage count of the facet is decremented.
All necessary thread locking occurs inside functions private to the
library, and the external semantics are kept simple and tidy. This
is hardly a major invention, or the only way to solve the problem,
but it illustrates that there is no need to hamstring other users
of locales to match the usage patterns favored by Rogue Wave.
I therefore *strongly* urge that the draft eliminate any suggestion
that caching of facets can occur on a use_facet call. Also, the
locale returned by locale::transparent() should be simply described
as an empty locale, and all references to undefined behavior for
such facets be removed.
num_get should add a get function (and underlying do_get) for
unsigned short and unsigned int extractions. Otherwise, input
values in the range -1 through -USHRT_MAX (or -UINT_MAX) look
erroneous, and cannot be distinguished from truly erroneous values.
num_get (and other facet get functions) should replace the
const locale& argument with an ios_base::iostate& argument, to
return any iostate flags. The locale is easily obtained from
the ios_base argument x, as x.getloc(), while the flags are a nuisance
to handle if returned in x. (Note that the put functions already
are prohibited from setting flags in x.) With these changes, I
believe the following example extractor from basic_istream satisfies
all the exception-handling requirements in the current draft:
Mytype& operator>>(long& X)
	{iostate stat = goodbit;
	if (ipfx())
		{const Myfacet& fac = use_facet<Myfacet>(getloc());
		try {
			fac.get(Myiter(rdbuf()), Myiter(0), (ios_base&)*this,
				stat, X); }
		catch (...) {
			setstate(badbit, Rethrow); }}	// added argument
	return (*this); }
num_put (and other facet put functions) should drop the const
locale& argument. All but the time_put functions should replace
this argument with a charT argument to specify the fill character.
The locale is easily obtained from the ios_base argument x, as
x.getloc(), while the fill character can no longer be obtained
from ios_base. (An insertion failure should be returned through
the added function failed() in ostreambuf_iterator, as described
under 24.4.4.)
numpunct::decimal point() and numpunct::thousands_sep() should
each return a single charT, just like their moneypunct counterparts.
Semantics of grouping is simpler, more sensible, and more consistent
with money facet (and the C Standard) with this change.
numpunct::grouping (and moneypunct::grouping later) should return
a string result, not a vector<char> result. Moreover, the encoding
for the c_str() representation should follow the same rules as for
localeconv()->grouping in C.
-------- Clause 23 Issues -------
The copy constructor for a deque (and all other containers in this
clause) always replaces its allocator with a default allocator.
This is surprising behavior. (Same is true of basic_string in clause
21.) Should supply a copy constructor that truly copies, then remove
default allocator argument from current constructor to disambiguate.
-------- Clause 24 Issues -------
istreambuf_iterator should remove all references to proxy, whether
or not Koenig's proposal passes to make more uniform the definition
of all input iterators. It is over specification.
ostreambuf_iterator should remove all references to equal, operator==,
and operator!=. Output iterators cannot be compared.
ostreambuf_iterator should add the member `bool failed() const',
which returns true only if an earlier insertion failed. It is needed
by num_put in to communicate insertion failures to inserters
in With this change, I believe the following example inserter
from basic_ostream satisfies all the exception-handling requirements
in the current draft:
Mytype& operator<<(long X)
	{iostate stat = goodbit;
	if (opfx())
		{const Myfacet& fac = use_facet<Myfacet>(getloc());
		try {
			if (fac.put(Myiter(rdbuf()), Myiter(0), (ios_base&)*this,
				stat, X).failed()
				stat |= badbit; }
		catch (...) {
			setstate(badbit, Rethrow); }}	// added argument
	return (*this); }
-------- Clause 25 Issues -------
for_each talks about a `non-constant function' when what is meant
is a function that doesn't alter its argument. In general `has no
side effects' really means this throughout clause 25.
lower_bound has no complexity clause. Should be same as for upper_bound.
upper_bound complexity is wrong. It is logarithmic only for random-access
iterators, otherwise linear.
equal_range complexity is wrong. Should be similar to upper_bound.
binary_search complexity is wrong. Should be similar to upper_bound.
lexicographical compare complexity is wrong. Should be twice as many
repetitions as stated.
transform has incorrect description of returns for unary operator.
Best fix is to change arguments to be first1 and last1, for uniformity.
unique_copy complexity requires only `last - first - 1' repetitions,
not 'last - first'.
-------- Clause 27 Issues -------
unsigned short (and unsigned int) extractors cannot use unsigned long
get function in num_get -- it cannot distinguish certain valid inputs
from errors. See above for a fix.
Revised description of exception handling is nonsense -- ``If the
called function throws an exception, the output function calls
setstate(badbit), which may throw ios_base::failure, in which case
it rethrows the exception.'' I think the intent is to say -- ``If
the called function throws an exception, the output function
calls setstate(badbit), which rethrows the exception if it would
otherwise throw ios_base::failure.'' This description is repeated
elsewhere, and needs fixing in all places. (Of course, how to pull
off this behavior is another matter. See example in 24.4.4 for one
useful extension to simplify this process.)
Table 88 *changes the long-standing default behavior for padding
output fields.* It has always been true that setting none of left,
right, and internal called for left padding (pad after text).
Now it calls for right padding (pad before text). Since this is
the initial state of all ios objects, *many simple C++ programs will
change behavior*. Fix is to have the table describe the effect
of right/internal/otherwise, as it has long been, rather than
left/internal/otherwise. Change was originally unauthorized, then
endorsed (I hope by accident) at the July '95 meeting.
Description of manipulators strongly suggests that smanip is a single
type. It was supposed to make clear that each manipulator can return
a different type, as needed. (And more than one type is certainly
needed here.)
setfill description is nonsense, since a fill character is now a
charT, which cannot necessarily be represented as type int. Nor
can it be applied to ios_base, since the fill character now
inhabits basic_ios. Needs a serious rewrite.