Doc. no. D????
Date: 2026-01-16
Project: Programming Language C++
Reply to: Jonathan Wakely <[email protected]>

C++ Standard Library Defect Reports and Accepted Issues (Revision D126)

Revised 2026-01-16 at 15:25:40 UTC

Reference ISO/IEC IS 14882:2024(E)

Also see:

This document contains only library issues which have been closed by the Library Working Group (LWG) after being found to be defects in the standard. That is, issues which have a status of DR, TC1, C++11, C++14, C++17, or Resolved. See the Library Closed Issues List for issues closed as non-defects. See the Library Active Issues List for active issues and more information. The introductory material in that document also applies to this document.

Revision History

Accepted Issues


1(i). C library linkage editing oversight

Section: 16.4.3.3 [using.linkage] Status: TC1 Submitter: Beman Dawes Opened: 1997-11-16 Last modified: 2016-08-09

Priority: Not Prioritized

View all other issues in [using.linkage].

View all issues with TC1 status.

Discussion:

The change specified in the proposed resolution below did not make it into the Standard. This change was accepted in principle at the London meeting, and the exact wording below was accepted at the Morristown meeting.

Proposed resolution:

Change 16.4.3.3 [using.linkage] paragraph 2 from:

It is unspecified whether a name from the Standard C library declared with external linkage has either extern "C" or extern "C++" linkage.

to:

Whether a name from the Standard C library declared with external linkage has extern "C" or extern "C++" linkage is implementation defined. It is recommended that an implementation use extern "C++" linkage for this purpose.


3(i). Atexit registration during atexit() call is not described

Section: 17.5 [support.start.term] Status: TC1 Submitter: Steve Clamage Opened: 1997-12-12 Last modified: 2016-08-09

Priority: Not Prioritized

View other active issues in [support.start.term].

View all other issues in [support.start.term].

View all issues with TC1 status.

Discussion:

We appear not to have covered all the possibilities of exit processing with respect to atexit registration.

Example 1: (C and C++)

    #include <stdlib.h>
    void f1() { }
    void f2() { atexit(f1); }
    
    int main()
    {
        atexit(f2); // the only use of f2
        return 0; // for C compatibility
    }

At program exit, f2 gets called due to its registration in main. Running f2 causes f1 to be newly registered during the exit processing. Is this a valid program? If so, what are its semantics?

Interestingly, neither the C standard, nor the C++ draft standard nor the forthcoming C9X Committee Draft says directly whether you can register a function with atexit during exit processing.

All 3 standards say that functions are run in reverse order of their registration. Since f1 is registered last, it ought to be run first, but by the time it is registered, it is too late to be first.

If the program is valid, the standards are self-contradictory about its semantics.

Example 2: (C++ only)

    
    void F() { static T t; } // type T has a destructor

    int main()
    {
        atexit(F); // the only use of F
    }

Function F registered with atexit has a local static variable t, and F is called for the first time during exit processing. A local static object is initialized the first time control flow passes through its definition, and all static objects are destroyed during exit processing. Is the code valid? If so, what are its semantics?

Section 18.3 "Start and termination" says that if a function F is registered with atexit before a static object t is initialized, F will not be called until after t's destructor completes.

In example 2, function F is registered with atexit before its local static object O could possibly be initialized. On that basis, it must not be called by exit processing until after O's destructor completes. But the destructor cannot be run until after F is called, since otherwise the object could not be constructed in the first place.

If the program is valid, the standard is self-contradictory about its semantics.

I plan to submit Example 1 as a public comment on the C9X CD, with a recommendation that the results be undefined. (Alternative: make it unspecified. I don't think it is worthwhile to specify the case where f1 itself registers additional functions, each of which registers still more functions.)

I think we should resolve the situation in the whatever way the C committee decides.

For Example 2, I recommend we declare the results undefined.

[See reflector message lib-6500 for further discussion.]

Proposed resolution:

Change section 18.3/8 from:

First, objects with static storage duration are destroyed and functions registered by calling atexit are called. Objects with static storage duration are destroyed in the reverse order of the completion of their constructor. (Automatic objects are not destroyed as a result of calling exit().) Functions registered with atexit are called in the reverse order of their registration. A function registered with atexit before an object obj1 of static storage duration is initialized will not be called until obj1's destruction has completed. A function registered with atexit after an object obj2 of static storage duration is initialized will be called before obj2's destruction starts.

to:

First, objects with static storage duration are destroyed and functions registered by calling atexit are called. Non-local objects with static storage duration are destroyed in the reverse order of the completion of their constructor. (Automatic objects are not destroyed as a result of calling exit().) Functions registered with atexit are called in the reverse order of their registration, except that a function is called after any previously registered functions that had already been called at the time it was registered. A function registered with atexit before a non-local object obj1 of static storage duration is initialized will not be called until obj1's destruction has completed. A function registered with atexit after a non-local object obj2 of static storage duration is initialized will be called before obj2's destruction starts. A local static object obj3 is destroyed at the same time it would be if a function calling the obj3 destructor were registered with atexit at the completion of the obj3 constructor.

Rationale:

See 99-0039/N1215, October 22, 1999, by Stephen D. Clamage for the analysis supporting to the proposed resolution.


5(i). String::compare specification questionable

Section: 27.4.3.7.8 [string.swap] Status: TC1 Submitter: Jack Reeves Opened: 1997-12-11 Last modified: 2016-11-12

Priority: Not Prioritized

View all other issues in [string.swap].

View all issues with TC1 status.

Duplicate of: 87

Discussion:

At the very end of the basic_string class definition is the signature: int compare(size_type pos1, size_type n1, const charT* s, size_type n2 = npos) const; In the following text this is defined as: returns basic_string<charT,traits,Allocator>(*this,pos1,n1).compare( basic_string<charT,traits,Allocator>(s,n2);

Since the constructor basic_string(const charT* s, size_type n, const Allocator& a = Allocator()) clearly requires that s != NULL and n < npos and further states that it throws length_error if n == npos, it appears the compare() signature above should always throw length error if invoked like so: str.compare(1, str.size()-1, s); where 's' is some null terminated character array.

This appears to be a typo since the obvious intent is to allow either the call above or something like: str.compare(1, str.size()-1, s, strlen(s)-1);

This would imply that what was really intended was two signatures int compare(size_type pos1, size_type n1, const charT* s) const int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const; each defined in terms of the corresponding constructor.

Proposed resolution:

Replace the compare signature in 27.4.3 [basic.string] (at the very end of the basic_string synopsis) which reads:

int compare(size_type pos1, size_type n1,
            const charT* s, size_type n2 = npos) const;

with:

int compare(size_type pos1, size_type n1,
            const charT* s) const;
int compare(size_type pos1, size_type n1,
            const charT* s, size_type n2) const;

Replace the portion of 27.4.3.7.8 [string.swap] paragraphs 5 and 6 which read:

int compare(size_type pos, size_type n1,
            charT * s, size_type n2 = npos) const;
Returns:
basic_string<charT,traits,Allocator>(*this, pos, n1).compare(
             basic_string<charT,traits,Allocator>( s, n2))

with:

int compare(size_type pos, size_type n1,
            const charT * s) const;
Returns:
basic_string<charT,traits,Allocator>(*this, pos, n1).compare(
             basic_string<charT,traits,Allocator>( s ))

int compare(size_type pos, size_type n1,
            const charT * s, size_type n2) const;
Returns:
basic_string<charT,traits,Allocator>(*this, pos, n1).compare(
             basic_string<charT,traits,Allocator>( s, n2))

Editors please note that in addition to splitting the signature, the third argument becomes const, matching the existing synopsis.

Rationale:

While the LWG dislikes adding signatures, this is a clear defect in the Standard which must be fixed.  The same problem was also identified in issues 7 (item 5) and 87.


7(i). String clause minor problems

Section: 27 [strings] Status: TC1 Submitter: Matt Austern Opened: 1997-12-15 Last modified: 2016-11-12

Priority: Not Prioritized

View all other issues in [strings].

View all issues with TC1 status.

Discussion:

(1) In 27.4.3.7.4 [string.insert], the description of template <class InputIterator> insert(iterator, InputIterator, InputIterator) makes no sense. It refers to a member function that doesn't exist. It also talks about the return value of a void function.

(2) Several versions of basic_string::replace don't appear in the class synopsis.

(3) basic_string::push_back appears in the synopsis, but is never described elsewhere. In the synopsis its argument is const charT, which doesn't makes much sense; it should probably be charT, or possible const charT&.

(4) basic_string::pop_back is missing.

(5) int compare(size_type pos, size_type n1, charT* s, size_type n2 = npos) make no sense. First, it's const charT* in the synopsis and charT* in the description. Second, given what it says in RETURNS, leaving out the final argument will always result in an exception getting thrown. This is paragraphs 5 and 6 of 27.4.3.7.8 [string.swap]

(6) In table 37, in section 27.2.2 [char.traits.require], there's a note for X::move(s, p, n). It says "Copies correctly even where p is in [s, s+n)". This is correct as far as it goes, but it doesn't go far enough; it should also guarantee that the copy is correct even where s in in [p, p+n). These are two orthogonal guarantees, and neither one follows from the other. Both guarantees are necessary if X::move is supposed to have the same sort of semantics as memmove (which was clearly the intent), and both guarantees are necessary if X::move is actually supposed to be useful.

Proposed resolution:

ITEM 1: In 21.3.5.4 [lib.string::insert], change paragraph 16 to

    EFFECTS: Equivalent to insert(p - begin(), basic_string(first, last)).

ITEM 2:  Not a defect; the Standard is clear.. There are ten versions of replace() in the synopsis, and ten versions in 21.3.5.6 [lib.string::replace].

ITEM 3: Change the declaration of push_back in the string synopsis (21.3, [lib.basic.string]) from:

     void push_back(const charT)

to

     void push_back(charT)

Add the following text immediately after 21.3.5.2 [lib.string::append], paragraph 10.

    void basic_string::push_back(charT c);
    EFFECTS: Equivalent to append(static_cast<size_type>(1), c);

ITEM 4: Not a defect. The omission appears to have been deliberate.

ITEM 5: Duplicate; see issue 5 (and 87).

ITEM 6: In table 37, Replace:

    "Copies correctly even where p is in [s, s+n)."

with:

     "Copies correctly even where the ranges [p, p+n) and [s, s+n) overlap."


8(i). Locale::global lacks guarantee

Section: 28.3.3.1.6 [locale.statics] Status: TC1 Submitter: Matt Austern Opened: 1997-12-24 Last modified: 2016-08-09

Priority: Not Prioritized

View all issues with TC1 status.

Discussion:

It appears there's an important guarantee missing from clause 22. We're told that invoking locale::global(L) sets the C locale if L has a name. However, we're not told whether or not invoking setlocale(s) sets the global C++ locale.

The intent, I think, is that it should not, but I can't find any such words anywhere.

Proposed resolution:

Add a sentence at the end of 28.3.3.1.6 [locale.statics], paragraph 2: 

No library function other than locale::global() shall affect the value returned by locale().


9(i). Operator new(0) calls should not yield the same pointer

Section: 17.6.3 [new.delete] Status: TC1 Submitter: Steve Clamage Opened: 1998-01-04 Last modified: 2016-08-09

Priority: Not Prioritized

View all other issues in [new.delete].

View all issues with TC1 status.

Discussion:

Scott Meyers, in a comp.std.c++ posting: I just noticed that section 3.7.3.1 of CD2 seems to allow for the possibility that all calls to operator new(0) yield the same pointer, an implementation technique specifically prohibited by ARM 5.3.3.Was this prohibition really lifted? Does the FDIS agree with CD2 in the regard? [Issues list maintainer's note: the IS is the same.]

Proposed resolution:

Change the last paragraph of 3.7.3 from:

Any allocation and/or deallocation functions defined in a C++ program shall conform to the semantics specified in 3.7.3.1 and 3.7.3.2.

to:

Any allocation and/or deallocation functions defined in a C++ program, including the default versions in the library, shall conform to the semantics specified in 3.7.3.1 and 3.7.3.2.

Change 3.7.3.1/2, next-to-last sentence, from :

If the size of the space requested is zero, the value returned shall not be a null pointer value (4.10).

to:

Even if the size of the space requested is zero, the request can fail. If the request succeeds, the value returned shall be a non-null pointer value (4.10) p0 different from any previously returned value p1, unless that value p1 was since passed to an operator delete.

5.3.4/7 currently reads:

When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements. The pointer returned by the new-expression is non-null. [Note: If the library allocation function is called, the pointer returned is distinct from the pointer to any other object.]

Retain the first sentence, and delete the remainder.

18.5.1 currently has no text. Add the following:

Except where otherwise specified, the provisions of 3.7.3 apply to the library versions of operator new and operator delete.

To 18.5.1.3, add the following text:

The provisions of 3.7.3 do not apply to these reserved placement forms of operator new and operator delete.

Rationale:

See 99-0040/N1216, October 22, 1999, by Stephen D. Clamage for the analysis supporting to the proposed resolution.


11(i). Bitset minor problems

Section: 22.9.2 [template.bitset] Status: TC1 Submitter: Matt Austern Opened: 1998-01-22 Last modified: 2016-08-09

Priority: Not Prioritized

View all other issues in [template.bitset].

View all issues with TC1 status.

Discussion:

(1) bitset<>::operator[] is mentioned in the class synopsis (23.3.5), but it is not documented in 23.3.5.2.

(2) The class synopsis only gives a single signature for bitset<>::operator[], reference operator[](size_t pos). This doesn't make much sense. It ought to be overloaded on const. reference operator[](size_t pos); bool operator[](size_t pos) const.

(3) Bitset's stream input function (23.3.5.3) ought to skip all whitespace before trying to extract 0s and 1s. The standard doesn't explicitly say that, though. This should go in the Effects clause.

Proposed resolution:

ITEMS 1 AND 2:

In the bitset synopsis (22.9.2 [template.bitset]), replace the member function

    reference operator[](size_t pos);

with the two member functions

    bool operator[](size_t pos) const;
    reference operator[](size_t pos);

Add the following text at the end of 22.9.2.3 [bitset.members], immediately after paragraph 45:

bool operator[](size_t pos) const;
Requires: pos is valid
Throws: nothing
Returns: test(pos)

bitset<N>::reference operator[](size_t pos);
Requires: pos is valid
Throws: nothing
Returns: An object of type bitset<N>::reference such that (*this)[pos] == this->test(pos), and such that (*this)[pos] = val is equivalent to this->set(pos, val);

Rationale:

The LWG believes Item 3 is not a defect. "Formatted input" implies the desired semantics. See 31.7.5.3 [istream.formatted].


13(i). Eos refuses to die

Section: 31.7.5.3.3 [istream.extractors] Status: TC1 Submitter: William M. Miller Opened: 1998-03-03 Last modified: 2017-04-22

Priority: Not Prioritized

View all other issues in [istream.extractors].

View all issues with TC1 status.

Discussion:

In 27.6.1.2.3, there is a reference to "eos", which is the only one in the whole draft (at least using Acrobat search), so it's undefined.

Proposed resolution:

In [istream::extractors], replace "eos" with "charT()"


14(i). Locale::combine should be const

Section: 28.3.3.1.4 [locale.members] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-08-09

Priority: Not Prioritized

View all other issues in [locale.members].

View all issues with TC1 status.

Discussion:

locale::combine is the only member function of locale (other than constructors and destructor) that is not const. There is no reason for it not to be const, and good reasons why it should have been const. Furthermore, leaving it non-const conflicts with 22.1.1 paragraph 6: "An instance of a locale is immutable."

History: this member function originally was a constructor. it happened that the interface it specified had no corresponding language syntax, so it was changed to a member function. As constructors are never const, there was no "const" in the interface which was transformed into member "combine". It should have been added at that time, but the omission was not noticed.

Proposed resolution:

In 28.3.3.1 [locale] and also in 28.3.3.1.4 [locale.members], add "const" to the declaration of member combine:

template <class Facet> locale combine(const locale& other) const; 

15(i). Locale::name requirement inconsistent

Section: 28.3.3.1.4 [locale.members] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-08-09

Priority: Not Prioritized

View all other issues in [locale.members].

View all issues with TC1 status.

Discussion:

locale::name() is described as returning a string that can be passed to a locale constructor, but there is no matching constructor.

Proposed resolution:

In 28.3.3.1.4 [locale.members], paragraph 5, replace "locale(name())" with "locale(name().c_str())".


16(i). Bad ctype_byname<char> decl

Section: 28.3.4.2.5 [locale.codecvt] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-08-09

Priority: Not Prioritized

View all other issues in [locale.codecvt].

View all issues with TC1 status.

Discussion:

The new virtual members ctype_byname<char>::do_widen and do_narrow did not get edited in properly. Instead, the member do_widen appears four times, with wrong argument lists.

Proposed resolution:

The correct declarations for the overloaded members do_narrow and do_widen should be copied from 28.3.4.2.4 [facet.ctype.special].


17(i). Bad bool parsing

Section: 28.3.4.3.2.3 [facet.num.get.virtuals] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-08-09

Priority: Not Prioritized

View other active issues in [facet.num.get.virtuals].

View all other issues in [facet.num.get.virtuals].

View all issues with TC1 status.

Discussion:

This section describes the process of parsing a text boolean value from the input stream. It does not say it recognizes either of the sequences "true" or "false" and returns the corresponding bool value; instead, it says it recognizes only one of those sequences, and chooses which according to the received value of a reference argument intended for returning the result, and reports an error if the other sequence is found. (!) Furthermore, it claims to get the names from the ctype<> facet rather than the numpunct<> facet, and it examines the "boolalpha" flag wrongly; it doesn't define the value "loc"; and finally, it computes wrongly whether to use numeric or "alpha" parsing.

I believe the correct algorithm is "as if":

  // in, err, val, and str are arguments.
  err = 0;
  const numpunct<charT>& np = use_facet<numpunct<charT> >(str.getloc());
  const string_type t = np.truename(), f = np.falsename();
  bool tm = true, fm = true;
  size_t pos = 0;
  while (tm && pos < t.size() || fm && pos < f.size()) {
    if (in == end) { err = str.eofbit; }
    bool matched = false;
    if (tm && pos < t.size()) {
      if (!err && t[pos] == *in) matched = true;
      else tm = false;
    }
    if (fm && pos < f.size()) {
      if (!err && f[pos] == *in) matched = true;
      else fm = false;
    }
    if (matched) { ++in; ++pos; }
    if (pos > t.size()) tm = false;
    if (pos > f.size()) fm = false;
  }
  if (tm == fm || pos == 0) { err |= str.failbit; }
  else                      { val = tm; }
  return in;

Notice this works reasonably when the candidate strings are both empty, or equal, or when one is a substring of the other. The proposed text below captures the logic of the code above.

Proposed resolution:

In 28.3.4.3.2.3 [facet.num.get.virtuals], in the first line of paragraph 14, change "&&" to "&".

Then, replace paragraphs 15 and 16 as follows:

Otherwise target sequences are determined "as if" by calling the members falsename() and truename() of the facet obtained by use_facet<numpunct<charT> >(str.getloc()). Successive characters in the range [in,end) (see [lib.sequence.reqmts]) are obtained and matched against corresponding positions in the target sequences only as necessary to identify a unique match. The input iterator in is compared to end only when necessary to obtain a character. If and only if a target sequence is uniquely matched, val is set to the corresponding value.

The in iterator is always left pointing one position beyond the last character successfully matched. If val is set, then err is set to str.goodbit; or to str.eofbit if, when seeking another character to match, it is found that (in==end). If val is not set, then err is set to str.failbit; or to (str.failbit|str.eofbit)if the reason for the failure was that (in==end). [Example: for targets true:"a" and false:"abb", the input sequence "a" yields val==true and err==str.eofbit; the input sequence "abc" yields err=str.failbit, with in ending at the 'c' element. For targets true:"1" and false:"0", the input sequence "1" yields val==true and err=str.goodbit. For empty targets (""), any input sequence yields err==str.failbit. --end example]


18(i). Get(...bool&) omitted

Section: 28.3.4.3.2.2 [facet.num.get.members] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-08-09

Priority: Not Prioritized

View all other issues in [facet.num.get.members].

View all issues with TC1 status.

Discussion:

In the list of num_get<> non-virtual members on page 22-23, the member that parses bool values was omitted from the list of definitions of non-virtual members, though it is listed in the class definition and the corresponding virtual is listed everywhere appropriate.

Proposed resolution:

Add at the beginning of 28.3.4.3.2.2 [facet.num.get.members] another get member for bool&, copied from the entry in 28.3.4.3.2 [locale.num.get].


19(i). "Noconv" definition too vague

Section: 28.3.4.2.5 [locale.codecvt] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-08-09

Priority: Not Prioritized

View all other issues in [locale.codecvt].

View all issues with TC1 status.

Duplicate of: 10

Discussion:

In the definitions of codecvt<>::do_out and do_in, they are specified to return noconv if "no conversion is needed". This definition is too vague, and does not say normatively what is done with the buffers.

Proposed resolution:

Change the entry for noconv in the table under paragraph 4 in section 28.3.4.2.5.3 [locale.codecvt.virtuals] to read:

noconv: internT and externT are the same type, and input sequence is identical to converted sequence.

Change the Note in paragraph 2 to normative text as follows:

If returns noconv, internT and externT are the same type and the converted sequence is identical to the input sequence [from,from_next). to_next is set equal to to, the value of state is unchanged, and there are no changes to the values in [to, to_limit).


20(i). Thousands_sep returns wrong type

Section: 28.3.4.4.1.3 [facet.numpunct.virtuals] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-08-09

Priority: Not Prioritized

View all issues with TC1 status.

Discussion:

The synopsis for numpunct<>::do_thousands_sep, and the definition of numpunct<>::thousands_sep which calls it, specify that it returns a value of type char_type. Here it is erroneously described as returning a "string_type".

Proposed resolution:

In 28.3.4.4.1.3 [facet.numpunct.virtuals], above paragraph 2, change "string_type" to "char_type".


21(i). Codecvt_byname<> instantiations

Section: 28.3.3.1.2.1 [locale.category] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [locale.category].

View all issues with TC1 status.

Discussion:

In the second table in the section, captioned "Required instantiations", the instantiations for codecvt_byname<> have been omitted. These are necessary to allow users to construct a locale by name from facets.

Proposed resolution:

Add in 28.3.3.1.2.1 [locale.category] to the table captioned "Required instantiations", in the category "ctype" the lines

codecvt_byname<char,char,mbstate_t>,
codecvt_byname<wchar_t,char,mbstate_t> 

22(i). Member open vs. flags

Section: 31.10.4.4 [ifstream.members] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [ifstream.members].

View all issues with TC1 status.

Discussion:

The description of basic_istream<>::open leaves unanswered questions about how it responds to or changes flags in the error status for the stream. A strict reading indicates that it ignores the bits and does not change them, which confuses users who do not expect eofbit and failbit to remain set after a successful open. There are three reasonable resolutions: 1) status quo 2) fail if fail(), ignore eofbit 3) clear failbit and eofbit on call to open().

Proposed resolution:

In 31.10.4.4 [ifstream.members] paragraph 3, and in 31.10.5.4 [ofstream.members] paragraph 3, under open() effects, add a footnote:

A successful open does not change the error state.

Rationale:

This may seem surprising to some users, but it's just an instance of a general rule: error flags are never cleared by the implementation. The only way error flags are are ever cleared is if the user explicitly clears them by hand.

The LWG believed that preserving this general rule was important enough so that an exception shouldn't be made just for this one case. The resolution of this issue clarifies what the LWG believes to have been the original intent.


23(i). Num_get overflow result

Section: 28.3.4.3.2.3 [facet.num.get.virtuals] Status: CD1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [facet.num.get.virtuals].

View all other issues in [facet.num.get.virtuals].

View all issues with CD1 status.

Discussion:

The current description of numeric input does not account for the possibility of overflow. This is an implicit result of changing the description to rely on the definition of scanf() (which fails to report overflow), and conflicts with the documented behavior of traditional and current implementations.

Users expect, when reading a character sequence that results in a value unrepresentable in the specified type, to have an error reported. The standard as written does not permit this.

Further comments from Dietmar:

I don't feel comfortable with the proposed resolution to issue 23: It kind of simplifies the issue to much. Here is what is going on:

Currently, the behavior of numeric overflow is rather counter intuitive and hard to trace, so I will describe it briefly:

Further discussion from Redmond:

The basic problem is that we've defined our behavior, including our error-reporting behavior, in terms of C90. However, C90's method of reporting overflow in scanf is not technically an "input error". The strto_* functions are more precise.

There was general consensus that failbit should be set upon overflow. We considered three options based on this:

  1. Set failbit upon conversion error (including overflow), and don't store any value.
  2. Set failbit upon conversion error, and also set errno to indicated the precise nature of the error.
  3. Set failbit upon conversion error. If the error was due to overflow, store +-numeric_limits<T>::max() as an overflow indication.

Straw poll: (1) 5; (2) 0; (3) 8.

Discussed at Lillehammer. General outline of what we want the solution to look like: we want to say that overflow is an error, and provide a way to distinguish overflow from other kinds of errors. Choose candidate field the same way scanf does, but don't describe the rest of the process in terms of format. If a finite input field is too large (positive or negative) to be represented as a finite value, then set failbit and assign the nearest representable value. Bill will provide wording.

Discussed at Toronto: N2327 is in alignment with the direction we wanted to go with in Lillehammer. Bill to work on.

Proposed resolution:

Change 28.3.4.3.2.3 [facet.num.get.virtuals], end of p3:

Stage 3: The result of stage 2 processing can be one of The sequence of chars accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header <cstdlib>:

The numeric value to be stored can be one of:

The resultant numeric value is stored in val.

Change 28.3.4.3.2.3 [facet.num.get.virtuals], p6-p7:

iter_type do_get(iter_type in, iter_type end, ios_base& str, 
                 ios_base::iostate& err, bool& val) const;

-6- Effects: If (str.flags()&ios_base::boolalpha)==0 then input proceeds as it would for a long except that if a value is being stored into val, the value is determined according to the following: If the value to be stored is 0 then false is stored. If the value is 1 then true is stored. Otherwise err|=ios_base::failbit is performed and no value true is stored. and ios_base::failbit is assigned to err.

-7- Otherwise target sequences are determined "as if" by calling the members falsename() and truename() of the facet obtained by use_facet<numpunct<charT> >(str.getloc()). Successive characters in the range [in,end) (see 23.1.1) are obtained and matched against corresponding positions in the target sequences only as necessary to identify a unique match. The input iterator in is compared to end only when necessary to obtain a character. If and only if a target sequence is uniquely matched, val is set to the corresponding value. Otherwise false is stored and ios_base::failbit is assigned to err.


24(i). "do_convert" doesn't exist

Section: 28.3.4.2.5 [locale.codecvt] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [locale.codecvt].

View all issues with TC1 status.

Duplicate of: 72

Discussion:

The description of codecvt<>::do_out and do_in mentions a symbol "do_convert" which is not defined in the standard. This is a leftover from an edit, and should be "do_in and do_out".

Proposed resolution:

In 28.3.4.2.5 [locale.codecvt], paragraph 3, change "do_convert" to "do_in or do_out". Also, in 28.3.4.2.5.3 [locale.codecvt.virtuals], change "do_convert()" to "do_in or do_out".


25(i). String operator<< uses width() value wrong

Section: 27.4.4.4 [string.io] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [string.io].

View all issues with TC1 status.

Duplicate of: 67

Discussion:

In the description of operator<< applied to strings, the standard says that uses the smaller of os.width() and str.size(), to pad "as described in stage 3" elsewhere; but this is inconsistent, as this allows no possibility of space for padding.

Proposed resolution:

Change 27.4.4.4 [string.io] paragraph 4 from:

    "... where n is the smaller of os.width() and str.size(); ..."

to:

    "... where n is the larger of os.width() and str.size(); ..."


26(i). Bad sentry example

Section: 31.7.5.2.4 [istream.sentry] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2021-06-06

Priority: Not Prioritized

View all other issues in [istream.sentry].

View all issues with TC1 status.

Discussion:

In paragraph 6, the code in the example:

  template <class charT, class traits = char_traits<charT> >
  basic_istream<charT,traits>::sentry(
           basic_istream<charT,traits>& is, bool noskipws = false) {
      ...
      int_type c;
      typedef ctype<charT> ctype_type;
      const ctype_type& ctype = use_facet<ctype_type>(is.getloc());
      while ((c = is.rdbuf()->snextc()) != traits::eof()) {
        if (ctype.is(ctype.space,c)==0) {
          is.rdbuf()->sputbackc (c);
          break;
        }
      }
      ...
   }

fails to demonstrate correct use of the facilities described. In particular, it fails to use traits operators, and specifies incorrect semantics. (E.g. it specifies skipping over the first character in the sequence without examining it.)

Proposed resolution:

Remove the example above from [istream::sentry] paragraph 6.

Rationale:

The originally proposed replacement code for the example was not correct. The LWG tried in Kona and again in Tokyo to correct it without success. In Tokyo, an implementor reported that actual working code ran over one page in length and was quite complicated. The LWG decided that it would be counter-productive to include such a lengthy example, which might well still contain errors.


27(i). String::erase(range) yields wrong iterator

Section: 27.4.3.7.5 [string.erase] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-11-12

Priority: Not Prioritized

View all other issues in [string.erase].

View all issues with TC1 status.

Discussion:

The string::erase(iterator first, iterator last) is specified to return an element one place beyond the next element after the last one erased. E.g. for the string "abcde", erasing the range ['b'..'d') would yield an iterator for element 'e', while 'd' has not been erased.

Proposed resolution:

In 27.4.3.7.5 [string.erase], paragraph 10, change:

Returns: an iterator which points to the element immediately following _last_ prior to the element being erased.

to read

Returns: an iterator which points to the element pointed to by _last_ prior to the other elements being erased.


28(i). Ctype<char>is ambiguous

Section: 28.3.4.2.4.3 [facet.ctype.char.members] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [facet.ctype.char.members].

View all issues with TC1 status.

Duplicate of: 236

Discussion:

The description of the vector form of ctype<char>::is can be interpreted to mean something very different from what was intended. Paragraph 4 says

Effects: The second form, for all *p in the range [low, high), assigns vec[p-low] to table()[(unsigned char)*p].

This is intended to copy the value indexed from table()[] into the place identified in vec[].

Proposed resolution:

Change 28.3.4.2.4.3 [facet.ctype.char.members], paragraph 4, to read

Effects: The second form, for all *p in the range [low, high), assigns into vec[p-low] the value table()[(unsigned char)*p].


29(i). Ios_base::init doesn't exist

Section: 31.4.3 [narrow.stream.objects] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [narrow.stream.objects].

View all issues with TC1 status.

Discussion:

Sections 31.4.3 [narrow.stream.objects] and 31.4.4 [wide.stream.objects] mention a function ios_base::init, which is not defined. Probably they mean basic_ios<>::init, defined in 31.5.4.2 [basic.ios.cons], paragraph 3.

Proposed resolution:

[R12: modified to include paragraph 5.]

In 31.4.3 [narrow.stream.objects] paragraph 2 and 5, change

ios_base::init

to

basic_ios<char>::init

Also, make a similar change in 31.4.4 [wide.stream.objects] except it should read

basic_ios<wchar_t>::init


30(i). Wrong header for LC_*

Section: 28.3.3.1.2.1 [locale.category] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [locale.category].

View all issues with TC1 status.

Discussion:

Paragraph 2 implies that the C macros LC_CTYPE etc. are defined in <cctype>, where they are in fact defined elsewhere to appear in <clocale>.

Proposed resolution:

In 28.3.3.1.2.1 [locale.category], paragraph 2, change "<cctype>" to read "<clocale>".


31(i). Immutable locale values

Section: 28.3.3.1 [locale] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [locale].

View all issues with TC1 status.

Duplicate of: 378

Discussion:

Paragraph 6, says "An instance of locale is immutable; once a facet reference is obtained from it, ...". This has caused some confusion, because locale variables are manifestly assignable.

Proposed resolution:

In 28.3.3.1 [locale] replace paragraph 6

An instance of locale is immutable; once a facet reference is obtained from it, that reference remains usable as long as the locale value itself exists.

with

Once a facet reference is obtained from a locale object by calling use_facet<>, that reference remains usable, and the results from member functions of it may be cached and re-used, as long as some locale object refers to that facet.


32(i). Pbackfail description inconsistent

Section: 31.6.3.5.4 [streambuf.virt.pback] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all issues with TC1 status.

Discussion:

The description of the required state before calling virtual member basic_streambuf<>::pbackfail requirements is inconsistent with the conditions described in 27.5.2.2.4 [lib.streambuf.pub.pback] where member sputbackc calls it. Specifically, the latter says it calls pbackfail if:

    traits::eq(c,gptr()[-1]) is false

where pbackfail claims to require:

    traits::eq(*gptr(),traits::to_char_type(c)) returns false

It appears that the pbackfail description is wrong.

Proposed resolution:

In 31.6.3.5.4 [streambuf.virt.pback], paragraph 1, change:

"traits::eq(*gptr(),traits::to_char_type( c))"

to

"traits::eq(traits::to_char_type(c),gptr()[-1])"

Rationale:

Note deliberate reordering of arguments for clarity in addition to the correction of the argument value.


33(i). Codecvt<> mentions from_type

Section: 28.3.4.2.5 [locale.codecvt] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [locale.codecvt].

View all issues with TC1 status.

Duplicate of: 43

Discussion:

In the table defining the results from do_out and do_in, the specification for the result error says

encountered a from_type character it could not convert

but from_type is not defined. This clearly is intended to be an externT for do_in, or an internT for do_out.

Proposed resolution:

In 28.3.4.2.5.3 [locale.codecvt.virtuals] paragraph 4, replace the definition in the table for the case of _error_ with

encountered a character in [from,from_end) that it could not convert.


34(i). True/falsename() not in ctype<>

Section: 28.3.4.3.3.3 [facet.num.put.virtuals] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [facet.num.put.virtuals].

View all other issues in [facet.num.put.virtuals].

View all issues with TC1 status.

Discussion:

In paragraph 19, Effects:, members truename() and falsename are used from facet ctype<charT>, but it has no such members. Note that this is also a problem in 22.2.2.1.2, addressed in (4).

Proposed resolution:

In 28.3.4.3.3.3 [facet.num.put.virtuals], paragraph 19, in the Effects: clause for member put(...., bool), replace the initialization of the string_type value s as follows:

const numpunct& np = use_facet<numpunct<charT> >(loc);
string_type s = val ? np.truename() : np.falsename(); 

35(i). No manipulator unitbuf in synopsis

Section: 31.5 [iostreams.base] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [iostreams.base].

View all issues with TC1 status.

Discussion:

In 31.5.5.1 [fmtflags.manip], we have a definition for a manipulator named "unitbuf". Unlike other manipulators, it's not listed in synopsis. Similarly for "nounitbuf".

Proposed resolution:

Add to the synopsis for <ios> in 31.5 [iostreams.base], after the entry for "nouppercase", the prototypes:

ios_base& unitbuf(ios_base& str);
ios_base& nounitbuf(ios_base& str); 

36(i). Iword & pword storage lifetime omitted

Section: 31.5.2.6 [ios.base.storage] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [ios.base.storage].

View all issues with TC1 status.

Discussion:

In the definitions for ios_base::iword and pword, the lifetime of the storage is specified badly, so that an implementation which only keeps the last value stored appears to conform. In particular, it says:

The reference returned may become invalid after another call to the object's iword member with a different index ...

This is not idle speculation; at least one implementation was done this way.

Proposed resolution:

Add in 31.5.2.6 [ios.base.storage], in both paragraph 2 and also in paragraph 4, replace the sentence:

The reference returned may become invalid after another call to the object's iword [pword] member with a different index, after a call to its copyfmt member, or when the object is destroyed.

with:

The reference returned is invalid after any other operations on the object. However, the value of the storage referred to is retained, so that until the next call to copyfmt, calling iword [pword] with the same index yields another reference to the same value.

substituting "iword" or "pword" as appropriate.


37(i). Leftover "global" reference

Section: 28.3.3.1 [locale] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [locale].

View all issues with TC1 status.

Discussion:

In the overview of locale semantics, paragraph 4, is the sentence

If Facet is not present in a locale (or, failing that, in the global locale), it throws the standard exception bad_cast.

This is not supported by the definition of use_facet<>, and represents semantics from an old draft.

Proposed resolution:

In 28.3.3.1 [locale], paragraph 4, delete the parenthesized expression

(or, failing that, in the global locale)


38(i). Facet definition incomplete

Section: 28.3.3.2 [locale.global.templates] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all issues with TC1 status.

Discussion:

It has been noticed by Esa Pulkkinen that the definition of "facet" is incomplete. In particular, a class derived from another facet, but which does not define a member id, cannot safely serve as the argument F to use_facet<F>(loc), because there is no guarantee that a reference to the facet instance stored in loc is safely convertible to F.

Proposed resolution:

In the definition of std::use_facet<>(), replace the text in paragraph 1 which reads:

Get a reference to a facet of a locale.

with:

Requires: Facet is a facet class whose definition contains the public static member id as defined in 28.3.3.1.2.2 [locale.facet].

[ Kona: strike as overspecification the text "(not inherits)" from the original resolution, which read "... whose definition contains (not inherits) the public static member id..." ]


39(i). istreambuf_iterator<>::operator++(int) definition garbled

Section: 24.6.4.4 [istreambuf.iterator.ops] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2017-11-29

Priority: Not Prioritized

View all other issues in [istreambuf.iterator.ops].

View all issues with TC1 status.

Discussion:

Following the definition of istreambuf_iterator<>::operator++(int) in paragraph 3, the standard contains three lines of garbage text left over from a previous edit.

istreambuf_iterator<charT,traits> tmp = *this;
sbuf_->sbumpc();
return(tmp); 

Proposed resolution:

In [istreambuf.iterator::op++], delete the three lines of code at the end of paragraph 3.


40(i). Meaningless normative paragraph in examples

Section: 99 [facets.examples] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [facets.examples].

View all issues with TC1 status.

Discussion:

Paragraph 3 of the locale examples is a description of part of an implementation technique that has lost its referent, and doesn't mean anything.

Proposed resolution:

Delete 99 [facets.examples] paragraph 3 which begins "This initialization/identification system depends...", or (at the editor's option) replace it with a place-holder to keep the paragraph numbering the same.


41(i). Ios_base needs clear(), exceptions()

Section: 31.5.2 [ios.base] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [ios.base].

View all issues with TC1 status.

Duplicate of: 157

Discussion:

The description of ios_base::iword() and pword() in 31.5.2.5 [ios.members.static], say that if they fail, they "set badbit, which may throw an exception". However, ios_base offers no interface to set or to test badbit; those interfaces are defined in basic_ios<>.

Proposed resolution:

Change the description in 31.5.2.6 [ios.base.storage] in paragraph 2, and also in paragraph 4, as follows. Replace

If the function fails it sets badbit, which may throw an exception.

with

If the function fails, and *this is a base sub-object of a basic_ios<> object or sub-object, the effect is equivalent to calling basic_ios<>::setstate(badbit) on the derived object (which may throw failure).

[Kona: LWG reviewed wording; setstate(failbit) changed to setstate(badbit).]


42(i). String ctors specify wrong default allocator

Section: 27.4.3 [basic.string] Status: TC1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [basic.string].

View all other issues in [basic.string].

View all issues with TC1 status.

Discussion:

The basic_string<> copy constructor:

basic_string(const basic_string& str, size_type pos = 0,
             size_type n = npos, const Allocator& a = Allocator()); 

specifies an Allocator argument default value that is counter-intuitive. The natural choice for a the allocator to copy from is str.get_allocator(). Though this cannot be expressed in default-argument notation, overloading suffices.

Alternatively, the other containers in Clause 23 (deque, list, vector) do not have this form of constructor, so it is inconsistent, and an evident source of confusion, for basic_string<> to have it, so it might better be removed.

Proposed resolution:

In 27.4.3 [basic.string], replace the declaration of the copy constructor as follows:

basic_string(const basic_string& str);
basic_string(const basic_string& str, size_type pos, size_type n = npos,
             const Allocator& a = Allocator());

In 27.4.3.2 [string.require], replace the copy constructor declaration as above. Add to paragraph 5, Effects:

In the first form, the Allocator value used is copied from str.get_allocator().

Rationale:

The LWG believes the constructor is actually broken, rather than just an unfortunate design choice.

The LWG considered two other possible resolutions:

A. In 27.4.3 [basic.string], replace the declaration of the copy constructor as follows:

basic_string(const basic_string& str, size_type pos = 0,
             size_type n = npos);
basic_string(const basic_string& str, size_type pos,
             size_type n, const Allocator& a); 

In 27.4.3.2 [string.require], replace the copy constructor declaration as above. Add to paragraph 5, Effects:

When no Allocator argument is provided, the string is constructed using the value str.get_allocator().

B. In 27.4.3 [basic.string], and also in 27.4.3.2 [string.require], replace the declaration of the copy constructor as follows:

basic_string(const basic_string& str, size_type pos = 0,
             size_type n = npos); 

The proposed resolution reflects the original intent of the LWG. It was also noted by Pete Becker that this fix "will cause a small amount of existing code to now work correctly."

[ Kona: issue editing snafu fixed - the proposed resolution now correctly reflects the LWG consensus. ]


44(i). Iostreams use operator== on int_type values

Section: 31 [input.output] Status: CD1 Submitter: Nathan Myers Opened: 1998-08-06 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [input.output].

View all issues with CD1 status.

Discussion:

Many of the specifications for iostreams specify that character values or their int_type equivalents are compared using operators == or !=, though in other places traits::eq() or traits::eq_int_type is specified to be used throughout. This is an inconsistency; we should change uses of == and != to use the traits members instead.

Proposed resolution:

[Pre-Kona: Dietmar supplied wording]

List of changes to clause 27:

  1. In lib.basic.ios.members paragraph 13 (postcondition clause for 'fill(cT)') change
         fillch == fill()
    
    to
         traits::eq(fillch, fill())
    
  2. In lib.istream.unformatted paragraph 7 (effects clause for 'get(cT,streamsize,cT)'), third bullet, change
         c == delim for the next available input character c
    
    to
         traits::eq(c, delim) for the next available input character c
    
  3. In lib.istream.unformatted paragraph 12 (effects clause for 'get(basic_streambuf<cT,Tr>&,cT)'), third bullet, change
         c == delim for the next available input character c
    
    to
         traits::eq(c, delim) for the next available input character c
    
  4. In lib.istream.unformatted paragraph 17 (effects clause for 'getline(cT,streamsize,cT)'), second bullet, change
         c == delim for the next available input character c
    
    to
         traits::eq(c, delim) for the next available input character c
      
  5. In lib.istream.unformatted paragraph 24 (effects clause for 'ignore(int,int_type)'), second bullet, change
         c == delim for the next available input character c
    
    to
         traits::eq_int_type(c, delim) for the next available input
         character c
    
  6. In lib.istream.unformatted paragraph 25 (notes clause for 'ignore(int,int_type)'), second bullet, change
         The last condition will never occur if delim == traits::eof()
    
    to
         The last condition will never occur if
         traits::eq_int_type(delim, traits::eof()).
    
  7. In lib.istream.sentry paragraph 6 (example implementation for the sentry constructor) change
         while ((c = is.rdbuf()->snextc()) != traits::eof()) {
    
    to
         while (!traits::eq_int_type(c = is.rdbuf()->snextc(), traits::eof())) {
    

List of changes to Chapter 21:

  1. In lib.string::find paragraph 1 (effects clause for find()), second bullet, change
         at(xpos+I) == str.at(I) for all elements ...
    
    to
         traits::eq(at(xpos+I), str.at(I)) for all elements ...
    
  2. In lib.string::rfind paragraph 1 (effects clause for rfind()), second bullet, change
         at(xpos+I) == str.at(I) for all elements ...
    
    to
         traits::eq(at(xpos+I), str.at(I)) for all elements ...
    
  3. In lib.string::find.first.of paragraph 1 (effects clause for find_first_of()), second bullet, change
         at(xpos+I) == str.at(I) for all elements ...
    
    to
         traits::eq(at(xpos+I), str.at(I)) for all elements ...
    
  4. In lib.string::find.last.of paragraph 1 (effects clause for find_last_of()), second bullet, change
         at(xpos+I) == str.at(I) for all elements ...
    
    to
         traits::eq(at(xpos+I), str.at(I)) for all elements ...
    
  5. In lib.string::find.first.not.of paragraph 1 (effects clause for find_first_not_of()), second bullet, change
         at(xpos+I) == str.at(I) for all elements ...
    
    to
         traits::eq(at(xpos+I), str.at(I)) for all elements ...
    
  6. In lib.string::find.last.not.of paragraph 1 (effects clause for find_last_not_of()), second bullet, change
         at(xpos+I) == str.at(I) for all elements ...
    
    to
         traits::eq(at(xpos+I), str.at(I)) for all elements ...
    
  7. In lib.string.ios paragraph 5 (effects clause for getline()), second bullet, change
         c == delim for the next available input character c 
    
    to
         traits::eq(c, delim) for the next available input character c 
    

Notes:


46(i). Minor Annex D errors

Section: 99 [depr.str.strstreams] Status: TC1 Submitter: Brendan Kehoe Opened: 1998-06-01 Last modified: 2016-01-28

Priority: Not Prioritized

View all issues with TC1 status.

Discussion:

See lib-6522 and edit-814.

Proposed resolution:

Change 99 [depr.strstreambuf] (since streambuf is a typedef of basic_streambuf<char>) from:

         virtual streambuf<char>* setbuf(char* s, streamsize n);

to:

         virtual streambuf* setbuf(char* s, streamsize n);

In [depr.strstream] insert the semicolon now missing after int_type:

     namespace std {
       class strstream
         : public basic_iostream<char> {
       public:
         // Types
         typedef char                                char_type;
         typedef typename char_traits<char>::int_type int_type
         typedef typename char_traits<char>::pos_type pos_type;

47(i). Imbue() and getloc() Returns clauses swapped

Section: 31.5.2.4 [ios.base.locales] Status: TC1 Submitter: Matt Austern Opened: 1998-06-21 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [ios.base.locales].

View all issues with TC1 status.

Discussion:

Section 27.4.2.3 specifies how imbue() and getloc() work. That section has two RETURNS clauses, and they make no sense as stated. They make perfect sense, though, if you swap them. Am I correct in thinking that paragraphs 2 and 4 just got mixed up by accident?

Proposed resolution:

In 31.5.2.4 [ios.base.locales] swap paragraphs 2 and 4.


48(i). Use of non-existent exception constructor

Section: 31.5.2.2.1 [ios.failure] Status: TC1 Submitter: Matt Austern Opened: 1998-06-21 Last modified: 2021-06-06

Priority: Not Prioritized

View all other issues in [ios.failure].

View all issues with TC1 status.

Discussion:

27.4.2.1.1, paragraph 2, says that class failure initializes the base class, exception, with exception(msg). Class exception (see 18.6.1) has no such constructor.

Proposed resolution:

Replace [ios::failure], paragraph 2, with

EFFECTS: Constructs an object of class failure.


49(i). Underspecification of ios_base::sync_with_stdio

Section: 31.5.2.5 [ios.members.static] Status: CD1 Submitter: Matt Austern Opened: 1998-06-21 Last modified: 2016-01-28

Priority: Not Prioritized

View all issues with CD1 status.

Discussion:

Two problems

(1) 27.4.2.4 doesn't say what ios_base::sync_with_stdio(f) returns. Does it return f, or does it return the previous synchronization state? My guess is the latter, but the standard doesn't say so.

(2) 27.4.2.4 doesn't say what it means for streams to be synchronized with stdio. Again, of course, I can make some guesses. (And I'm unhappy about the performance implications of those guesses, but that's another matter.)

Proposed resolution:

Change the following sentence in 31.5.2.5 [ios.members.static] returns clause from:

true if the standard iostream objects (27.3) are synchronized and otherwise returns false.

to:

true if the previous state of the standard iostream objects (27.3) was synchronized and otherwise returns false.

Add the following immediately after 31.5.2.5 [ios.members.static], paragraph 2:

When a standard iostream object str is synchronized with a standard stdio stream f, the effect of inserting a character c by

  fputc(f, c);

is the same as the effect of

  str.rdbuf()->sputc(c);

for any sequence of characters; the effect of extracting a character c by

  c = fgetc(f);

is the same as the effect of:

  c = str.rdbuf()->sbumpc(c);

for any sequences of characters; and the effect of pushing back a character c by

  ungetc(c, f);

is the same as the effect of

  str.rdbuf()->sputbackc(c);

for any sequence of characters. [Footnote: This implies that operations on a standard iostream object can be mixed arbitrarily with operations on the corresponding stdio stream. In practical terms, synchronization usually means that a standard iostream object and a standard stdio object share a buffer. --End Footnote]

[pre-Copenhagen: PJP and Matt contributed the definition of "synchronization"]

[post-Copenhagen: proposed resolution was revised slightly: text was added in the non-normative footnote to say that operations on the two streams can be mixed arbitrarily.]


50(i). Copy constructor and assignment operator of ios_base

Section: 31.5.2 [ios.base] Status: TC1 Submitter: Matt Austern Opened: 1998-06-21 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [ios.base].

View all issues with TC1 status.

Discussion:

As written, ios_base has a copy constructor and an assignment operator. (Nothing in the standard says it doesn't have one, and all classes have copy constructors and assignment operators unless you take specific steps to avoid them.) However, nothing in 27.4.2 says what the copy constructor and assignment operator do.

My guess is that this was an oversight, that ios_base is, like basic_ios, not supposed to have a copy constructor or an assignment operator.

Jerry Schwarz comments: Yes, its an oversight, but in the opposite sense to what you're suggesting. At one point there was a definite intention that you could copy ios_base. It's an easy way to save the entire state of a stream for future use. As you note, to carry out that intention would have required a explicit description of the semantics (e.g. what happens to the iarray and parray stuff).

Proposed resolution:

In 31.5.2 [ios.base], class ios_base, specify the copy constructor and operator= members as being private.

Rationale:

The LWG believes the difficulty of specifying correct semantics outweighs any benefit of allowing ios_base objects to be copyable.


51(i). Requirement to not invalidate iterators missing

Section: 23.2 [container.requirements] Status: TC1 Submitter: David Vandevoorde Opened: 1998-06-23 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [container.requirements].

View all issues with TC1 status.