Doc. no. N2729=08-0239
Date: 2008-08-24
Project: Programming Language C++
Reply to: Howard Hinnant <howard.hinnant@gmail.com>

C++ Standard Library Closed Issues List (Revision R59)

Reference ISO/IEC IS 14882:1998(E)

Also see:

This document contains only library issues which have been closed by the Library Working Group as duplicates or not defects. That is, issues which have a status of Dup or NAD. See the Library Active Issues List active issues and more information. See the Library Defect Reports List for issues considered defects. The introductory material in that document also applies to this document.

Revision History

Closed Issues


2. Auto_ptr conversions effects incorrect

Section: D.9.1.3 [auto.ptr.conv] Status: NAD Submitter: Nathan Myers Date: 1997-12-04

View all issues with NAD status.

Discussion:

Paragraph 1 in "Effects", says "Calls p->release()" where it clearly must be "Calls p.release()". (As it is, it seems to require using auto_ptr<>::operator-> to refer to X::release, assuming that exists.)

Proposed resolution:

Change 20.5.4.3 [meta.unary.prop] paragraph 1 Effects from "Calls p->release()" to "Calls p.release()".

Rationale:

Not a defect: the proposed change is already found in the standard. [Originally classified as a defect, later reclassified.]


4. Basic_string size_type and difference_type should be implementation defined

Section: 21.3 [basic.string] Status: NAD Submitter: Beman Dawes Date: 1997-11-16

View other active issues in [basic.string].

View all other issues in [basic.string].

View all issues with NAD status.

Discussion:

In Morristown we changed the size_type and difference_type typedefs for all the other containers to implementation defined with a reference to 23.1 [container.requirements]. This should probably also have been done for strings.

Rationale:

Not a defect. [Originally classified as a defect, later reclassified.] basic_string, unlike the other standard library template containers, is severely constrained by its use of char_traits. Those types are dictated by the traits class, and are far from implementation defined.


6. File position not an offset unimplementable

Section: 27.4.3 [fpos] Status: NAD Submitter: Matt Austern Date: 1997-12-15

View all other issues in [fpos].

View all issues with NAD status.

Discussion:

Table 88, in I/O, is too strict; it's unimplementable on systems where a file position isn't just an offset. It also never says just what fpos<> is really supposed to be. [Here's my summary, which Jerry agrees is more or less accurate. "I think I now know what the class really is, at this point: it's a magic cookie that encapsulates an mbstate_t and a file position (possibly represented as an fpos_t), it has syntactic support for pointer-like arithmetic, and implementors are required to have real, not just syntactic, support for arithmetic." This isn't standardese, of course.]

Rationale:

Not a defect. The LWG believes that the Standard is already clear, and that the above summary is what the Standard in effect says.


10. Codecvt<>::do unclear

Section: 22.2.1.5 [locale.codecvt.byname] Status: Dup Submitter: Matt Austern Date: 1998-01-14

View all other issues in [locale.codecvt.byname].

View all issues with Dup status.

Duplicate of: 19

Discussion:

Section 22.2.1.5.2 says that codecvt<>::do_in and do_out should return the value noconv if "no conversion was needed". However, I don't see anything anywhere that defines what it means for a conversion to be needed or not needed. I can think of several circumstances where one might plausibly think that a conversion is not "needed", but I don't know which one is intended here.

Rationale:


12. Way objects hold allocators unclear

Section: 20.1.2 [allocator.requirements] Status: NAD Submitter: Angelika Langer Date: 1998-02-23

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

I couldn't find a statement in the standard saying whether the allocator object held by a container is held as a copy of the constructor argument or whether a pointer of reference is maintained internal. There is an according statement for compare objects and how they are maintained by the associative containers, but I couldn't find anything regarding allocators.

Did I overlook it? Is it an open issue or known defect? Or is it deliberately left unspecified?

Rationale:

Not a defect. The LWG believes that the Standard is already clear.  See 23.1 [container.requirements], paragraph 8.


43. Locale table correction

Section: 22.2.1.5 [locale.codecvt.byname] Status: Dup Submitter: Brendan Kehoe Date: 1998-06-01

View all other issues in [locale.codecvt.byname].

View all issues with Dup status.

Duplicate of: 33

Discussion:

Rationale:


45. Stringstreams read/write pointers initial position unclear

Section: 27.7.3 [ostringstream] Status: NAD Submitter: Matthias Mueller Date: 1998-05-27

View all issues with NAD status.

Discussion:

In a comp.lang.c++.moderated Matthias Mueller wrote:

"We are not sure how to interpret the CD2 (see 27.2 [iostream.forward], 27.7.3.1 [ostringstream.cons], 27.7.1.1 [stringbuf.cons]) with respect to the question as to what the correct initial positions of the write and  read pointers of a stringstream should be."

"Is it the same to output two strings or to initialize the stringstream with the first and to output the second?"

[PJ Plauger, Bjarne Stroustrup, Randy Smithey, Sean Corfield, and Jerry Schwarz have all offered opinions; see reflector messages lib-6518, 6519, 6520, 6521, 6523, 6524.]

Rationale:

The LWG believes the Standard is correct as written. The behavior of stringstreams is consistent with fstreams, and there is a constructor which can be used to obtain the desired effect. This behavior is known to be different from strstreams.


58. Extracting a char from a wide-oriented stream

Section: 27.6.1.2.3 [istream::extractors] Status: NAD Submitter: Matt Austern Date: 1998-07-01

View all other issues in [istream::extractors].

View all issues with NAD status.

Discussion:

27.6.1.2.3 has member functions for extraction of signed char and unsigned char, both singly and as strings. However, it doesn't say what it means to extract a char from a basic_streambuf<charT, Traits>.

basic_streambuf, after all, has no members to extract a char, so basic_istream must somehow convert from charT to signed char or unsigned char. The standard doesn't say how it is to perform that conversion.

Rationale:

The Standard is correct as written. There is no such extractor and this is the intent of the LWG.


65. Underspecification of strstreambuf::seekoff

Section: D.7.1.3 [depr.strstreambuf.virtuals] Status: NAD Submitter: Matt Austern Date: 1998-08-18

View all other issues in [depr.strstreambuf.virtuals].

View all issues with NAD status.

Discussion:

The standard says how this member function affects the current stream position. (gptr or pptr) However, it does not say how this member function affects the beginning and end of the get/put area.

This is an issue when seekoff is used to position the get pointer beyond the end of the current read area. (Which is legal. This is implicit in the definition of seekhigh in D.7.1, paragraph 4.)

Rationale:

The LWG agrees that seekoff() is underspecified, but does not wish to invest effort in this deprecated feature.


67. Setw useless for strings

Section: 21.3.8.9 [string.io] Status: Dup Submitter: Steve Clamage Date: 1998-07-09

View all other issues in [string.io].

View all issues with Dup status.

Duplicate of: 25

Discussion:

In a comp.std.c++ posting Michel Michaud wrote: What should be output by:

   string text("Hello");
   cout << '[' << setw(10) << right << text << ']';

Shouldn't it be:

   [     Hello]

Another person replied: Actually, according to the FDIS, the width of the field should be the minimum of width and the length of the string, so the output shouldn't have any padding. I think that this is a typo, however, and that what is wanted is the maximum of the two. (As written, setw is useless for strings. If that had been the intent, one wouldn't expect them to have mentioned using its value.)

It's worth pointing out that this is a recent correction anyway; IIRC, earlier versions of the draft forgot to mention formatting parameters whatsoever.

Rationale:


72. Do_convert phantom member function

Section: 22.2.1.4 [locale.codecvt] Status: Dup Submitter: Nathan Myers Date: 1998-08-24

View all other issues in [locale.codecvt].

View all issues with Dup status.

Duplicate of: 24

Discussion:

In 22.2.1.4 [locale.codecvt] par 3, and in 22.2.1.4.2 [locale.codecvt.virtuals] par 8, a nonexistent member function "do_convert" is mentioned. This member was replaced with "do_in" and "do_out", the proper referents in the contexts above.

Rationale:


73. is_open should be const

Section: 27.8.1 [fstreams] Status: NAD Submitter: Matt Austern Date: 1998-08-27

View all other issues in [fstreams].

View all issues with NAD status.

Discussion:

Classes basic_ifstream, basic_ofstream, and basic_fstream all have a member function is_open. It should be a const member function, since it does nothing but call one of basic_filebuf's const member functions.

Rationale:

Not a defect. This is a deliberate feature; const streams would be meaningless.


77. Valarray operator[] const returning value

Section: 26.5.2.3 [valarray.access] Status: Dup Submitter: Levente Farkas Date: 1998-09-09

View all other issues in [valarray.access].

View all issues with Dup status.

Duplicate of: 389

Discussion:

valarray:

    T operator[] (size_t) const;

why not

    const T& operator[] (size_t) const;

as in vector ???

One can't copy even from a const valarray eg:

    memcpy(ptr, &v[0], v.size() * sizeof(double));

[I] find this bug in valarray is very difficult.

Rationale:

The LWG believes that the interface was deliberately designed that way. That is what valarray was designed to do; that's where the "value array" name comes from. LWG members further comment that "we don't want valarray to be a full STL container." 26.5.2.3 [valarray.access] specifies properties that indicate "an absence of aliasing" for non-constant arrays; this allows optimizations, including special hardware optimizations, that are not otherwise possible.


81. Wrong declaration of slice operations

Section: 26.5.5 [template.slice.array], 26.5.7 [template.gslice.array], 26.5.8 [template.mask.array], 26.5.9 [template.indirect.array] Status: NAD Submitter: Nico Josuttis Date: 1998-09-29

View all other issues in [template.slice.array].

View all issues with NAD status.

Discussion:

Isn't the definition of copy constructor and assignment operators wrong?        Instead of

      slice_array(const slice_array&); 
      slice_array& operator=(const slice_array&);

IMHO they have to be

      slice_array(const slice_array<T>&); 
      slice_array& operator=(const slice_array<T>&);

Same for gslice_array.

Rationale:

Not a defect. The Standard is correct as written.


82. Missing constant for set elements

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Nico Josuttis Date: 1998-09-29

View all other issues in [associative.reqmts].

View all issues with NAD status.

Discussion:

Paragraph 5 specifies:

For set and multiset the value type is the same as the key type. For map and multimap it is equal to pair<const Key, T>.

Strictly speaking, this is not correct because for set and multiset the value type is the same as the constant key type.

Rationale:

Not a defect. The Standard is correct as written; it uses a different mechanism (const &) for set and multiset. See issue 103 for a related issue.


84. Ambiguity with string::insert()

Section: 21.3.5 [string.access] Status: NAD Submitter: Nico Josuttis Date: 1998-09-29

View all issues with NAD status.

Discussion:

If I try

    s.insert(0,1,' ');

  I get an nasty ambiguity. It might be

    s.insert((size_type)0,(size_type)1,(charT)' ');

which inserts 1 space character at position 0, or

    s.insert((char*)0,(size_type)1,(charT)' ')

which inserts 1 space character at iterator/address 0 (bingo!), or

    s.insert((char*)0, (InputIterator)1, (InputIterator)' ')

which normally inserts characters from iterator 1 to iterator ' '. But according to 23.1.1.9 (the "do the right thing" fix) it is equivalent to the second. However, it is still ambiguous, because of course I mean the first!

Rationale:

Not a defect. The LWG believes this is a "genetic misfortune" inherent in the design of string and thus not a defect in the Standard as such .


85. String char types

Section: 21 [strings] Status: NAD Submitter: Nico Josuttis Date: 1998-09-29

View all other issues in [strings].

View all issues with NAD status.

Discussion:

The standard seems not to require that charT is equivalent to traits::char_type. So, what happens if charT is not equivalent to traits::char_type?

Rationale:

There is already wording in 21.1 [char.traits] paragraph 3 that requires them to be the same.


87. Error in description of string::compare()

Section: 21.3.6.8 [string::swap] Status: Dup Submitter: Nico Josuttis Date: 1998-09-29

View all other issues in [string::swap].

View all issues with Dup status.

Duplicate of: 5

Discussion:

The following compare() description is obviously a bug:

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

because without passing n2 it should compare up to the end of the string instead of comparing npos characters (which throws an exception)

Rationale:


88. Inconsistency between string::insert() and string::append()

Section: 21.3.6.4 [string::insert], 21.3.6.2 [string::append] Status: NAD Submitter: Nico Josuttis Date: 1998-09-29

View all other issues in [string::insert].

View all issues with NAD status.

Discussion:

Why does

  template<class InputIterator> 
       basic_string& append(InputIterator first, InputIterator last);

return a string, while

  template<class InputIterator> 
       void insert(iterator p, InputIterator first, InputIterator last);

returns nothing ?

Rationale:

The LWG believes this stylistic inconsistency is not sufficiently serious to constitute a defect.


89. Missing throw specification for string::insert() and string::replace()

Section: 21.3.6.4 [string::insert], 21.3.6.6 [string::replace] Status: Dup Submitter: Nico Josuttis Date: 1998-09-29

View all other issues in [string::insert].

View all issues with Dup status.

Duplicate of: 83

Discussion:

All insert() and replace() members for strings with an iterator as first argument lack a throw specification. The throw specification should probably be: length_error if size exceeds maximum.

Rationale:

Considered a duplicate because it will be solved by the resolution of issue 83.


93. Incomplete Valarray Subset Definitions

Section: 26.5 [numarray] Status: NAD Submitter: Nico Josuttis Date: 1998-09-29

View all other issues in [numarray].

View all issues with NAD status.

Discussion:

You can easily create subsets, but you can't easily combine them with other subsets. Unfortunately, you almost always needs an explicit type conversion to valarray. This is because the standard does not specify that valarray subsets provide the same operations as valarrays.

For example, to multiply two subsets and assign the result to a third subset, you can't write the following:

va[slice(0,4,3)] = va[slice(1,4,3)] * va[slice(2,4,3)];

Instead, you have to code as follows:

va[slice(0,4,3)] = static_cast<valarray<double> >(va[slice(1,4,3)]) * 
                   static_cast<valarray<double> >(va[slice(2,4,3)]);

This is tedious and error-prone. Even worse, it costs performance because each cast creates a temporary objects, which could be avoided without the cast.

Proposed resolution:

Extend all valarray subset types so that they offer all valarray operations.

Rationale:

This is not a defect in the Standard; it is a request for an extension.


94. May library implementors add template parameters to Standard Library classes?

Section: 17.4.4 [conforming] Status: NAD Submitter: Matt Austern Date: 1998-01-22

View all issues with NAD status.

Discussion:

Is it a permitted extension for library implementors to add template parameters to standard library classes, provided that those extra parameters have defaults? For example, instead of defining template <class T, class Alloc = allocator<T> > class vector; defining it as template <class T, class Alloc = allocator<T>, int N = 1> class vector;

The standard may well already allow this (I can't think of any way that this extension could break a conforming program, considering that users are not permitted to forward-declare standard library components), but it ought to be explicitly permitted or forbidden.

comment from Steve Cleary via comp.std.c++:

I disagree [with the proposed resolution] for the following reason: consider user library code with template template parameters. For example, a user library object may be templated on the type of underlying sequence storage to use (deque/list/vector), since these classes all take the same number and type of template parameters; this would allow the user to determine the performance tradeoffs of the user library object. A similar example is a user library object templated on the type of underlying set storage (set/multiset) or map storage (map/multimap), which would allow users to change (within reason) the semantic meanings of operations on that object.

I think that additional template parameters should be forbidden in the Standard classes. Library writers don't lose any expressive power, and can still offer extensions because additional template parameters may be provided by a non-Standard implementation class:

 
   template <class T, class Allocator = allocator<T>, int N = 1>
   class __vector
   { ... };
   template <class T, class Allocator = allocator<T> >
   class vector: public __vector<T, Allocator>
   { ... };

Proposed resolution:

Add a new subclause [presumably 17.4.4.9] following 17.4.4.9 [res.on.exception.handling]:

17.4.4.9 Template Parameters

A specialization of a template class described in the C++ Standard Library behaves the same as if the implementation declares no additional template parameters.

Footnote: Additional template parameters with default values are thus permitted.

Add "template parameters" to the list of subclauses at the end of 17.4.4 [conforming] paragraph 1.

[Kona: The LWG agreed the standard needs clarification. After discussion with John Spicer, it seems added template parameters can be detected by a program using template-template parameters. A straw vote - "should implementors be allowed to add template parameters?" found no consensus ; 5 - yes, 7 - no.]

Rationale:

There is no ambiguity; the standard is clear as written. Library implementors are not permitted to add template parameters to standard library classes. This does not fall under the "as if" rule, so it would be permitted only if the standard gave explicit license for implementors to do this. This would require a change in the standard.

The LWG decided against making this change, because it would break user code involving template template parameters or specializations of standard library class templates.


95. Members added by the implementation

Section: 17.4.4.4 [member.functions] Status: NAD Submitter: AFNOR Date: 1998-10-07

View all issues with NAD status.

Discussion:

In 17.3.4.4/2 vs 17.3.4.7/0 there is a hole; an implementation could add virtual members a base class and break user derived classes.

Example:

// implementation code:
struct _Base { // _Base is in the implementer namespace
        virtual void foo ();
};
class vector : _Base // deriving from a class is allowed
{ ... };

// user code:
class vector_checking : public vector 
{
        void foo (); // don't want to override _Base::foo () as the 
                     // user doesn't know about _Base::foo ()
};

Proposed resolution:

Clarify the wording to make the example illegal.

Rationale:

This is not a defect in the Standard.  The example is already illegal.  See 17.4.4.4 [member.functions] paragraph 2.


97. Insert inconsistent definition

Section: 23 [containers] Status: NAD Submitter: AFNOR Date: 1998-10-07

View other active issues in [containers].

View all other issues in [containers].

View all issues with NAD status.

Discussion:

insert(iterator, const value_type&) is defined both on sequences and on set, with unrelated semantics: insert here (in sequences), and insert with hint (in associative containers). They should have different names (B.S. says: do not abuse overloading).

Rationale:

This is not a defect in the Standard. It is a genetic misfortune of the design, for better or for worse.


99. Reverse_iterator comparisons completely wrong

Section: 24.4.1.3.13 [reverse.iter.op==] Status: NAD Submitter: AFNOR Date: 1998-10-07

View all issues with NAD status.

Discussion:

The <, >, <=, >= comparison operator are wrong: they return the opposite of what they should.

Note: same problem in CD2, these were not even defined in CD1. SGI STL code is correct; this problem is known since the Morristown meeting but there it was too late

Rationale:

This is not a defect in the Standard. A careful reading shows the Standard is correct as written. A review of several implementations show that they implement exactly what the Standard says.


100. Insert iterators/ostream_iterators overconstrained

Section: 24.4.2 [insert.iterators], 24.5.4 [ostreambuf.iterator] Status: NAD Submitter: AFNOR Date: 1998-10-07

View all issues with NAD status.

Discussion:

Overspecified For an insert iterator it, the expression *it is required to return a reference to it. This is a simple possible implementation, but as the SGI STL documentation says, not the only one, and the user should not assume that this is the case.

Rationale:

The LWG believes this causes no harm and is not a defect in the standard. The only example anyone could come up with caused some incorrect code to work, rather than the other way around.


101. No way to free storage for vector and deque

Section: 23.2.6 [vector], 23.2.1 [array] Status: NAD Submitter: AFNOR Date: 1998-10-07

View all other issues in [vector].

View all issues with NAD status.

Discussion:

Reserve can not free storage, unlike string::reserve

Rationale:

This is not a defect in the Standard. The LWG has considered this issue in the past and sees no need to change the Standard. Deque has no reserve() member function. For vector, shrink-to-fit can be expressed in a single line of code (where v is vector<T>):

vector<T>(v).swap(v);  // shrink-to-fit v


102. Bug in insert range in associative containers

Section: 23.1.4 [associative.reqmts] Status: Dup Submitter: AFNOR Date: 1998-10-07

View all other issues in [associative.reqmts].

View all issues with Dup status.

Duplicate of: 264

Discussion:

Table 69 of Containers say that a.insert(i,j) is linear if [i, j) is ordered. It seems impossible to implement, as it means that if [i, j) = [x], insert in an associative container is O(1)!

Proposed resolution:

N+log (size()) if [i,j) is sorted according to value_comp()

Rationale:

Subsumed by issue 264.


104. Description of basic_string::operator[] is unclear

Section: 21.3.4 [string.capacity] Status: NAD Submitter: AFNOR Date: 1998-10-07

View all other issues in [string.capacity].

View all issues with NAD status.

Discussion:

It is not clear that undefined behavior applies when pos == size () for the non const version.

Proposed resolution:

Rewrite as: Otherwise, if pos > size () or pos == size () and the non-const version is used, then the behavior is undefined.

Rationale:

The Standard is correct. The proposed resolution already appears in the Standard.


105. fstream ctors argument types desired

Section: 27.8 [file.streams] Status: Dup Submitter: AFNOR Date: 1998-10-07

View all issues with Dup status.

Duplicate of: 454

Discussion:

fstream ctors take a const char* instead of string.
fstream ctors can't take wchar_t

An extension to add a const wchar_t* to fstream would make the implementation non conforming.

Rationale:

This is not a defect in the Standard. It might be an interesting extension for the next Standard.


107. Valarray constructor is strange

Section: 26.5.2 [template.valarray] Status: NAD Submitter: AFNOR Date: 1998-10-07

View all other issues in [template.valarray].

View all issues with NAD status.

Discussion:

The order of the arguments is (elem, size) instead of the normal (size, elem) in the rest of the library. Since elem often has an integral or floating point type, both types are convertible to each other and reversing them leads to a well formed program.

Proposed resolution:

Inverting the arguments could silently break programs. Introduce the two signatures (const T&, size_t) and (size_t, const T&), but make the one we do not want private so errors result in a diagnosed access violation. This technique can also be applied to STL containers.

Rationale:

The LWG believes that while the order of arguments is unfortunate, it does not constitute a defect in the standard. The LWG believes that the proposed solution will not work for valarray<size_t> and perhaps other cases.


111. istreambuf_iterator::equal overspecified, inefficient

Section: 24.5.3.5 [istreambuf.iterator::equal] Status: NAD Future Submitter: Nathan Myers Date: 1998-10-15

View all issues with NAD Future status.

Discussion:

The member istreambuf_iterator<>::equal is specified to be unnecessarily inefficient. While this does not affect the efficiency of conforming implementations of iostreams, because they can "reach into" the iterators and bypass this function, it does affect users who use istreambuf_iterators.

The inefficiency results from a too-scrupulous definition, which requires a "true" result if neither iterator is at eof. In practice these iterators can only usefully be compared with the "eof" value, so the extra test implied provides no benefit, but slows down users' code.

The solution is to weaken the requirement on the function to return true only if both iterators are at eof.

Proposed resolution:

Replace 24.5.3.5 [istreambuf.iterator::equal], paragraph 1,

-1- Returns: true if and only if both iterators are at end-of-stream, or neither is at end-of-stream, regardless of what streambuf object they use.

with

-1- Returns: true if and only if both iterators are at end-of-stream, regardless of what streambuf object they use.

Rationale:

It is not clear that this is a genuine defect. Additionally, the LWG was reluctant to make a change that would result in operator== not being a equivalence relation. One consequence of this change is that an algorithm that's passed the range [i, i) would no longer treat it as an empty range.


113. Missing/extra iostream sync semantics

Section: 27.6.1.1 [istream], 27.6.1.3 [istream.unformatted] Status: NAD Submitter: Steve Clamage Date: 1998-10-13

View all other issues in [istream].

View all issues with NAD status.

Discussion:

In 27.6.1.1, class basic_istream has a member function sync, described in 27.6.1.3, paragraph 36.

Following the chain of definitions, I find that the various sync functions have defined semantics for output streams, but no semantics for input streams. On the other hand, basic_ostream has no sync function.

The sync function should at minimum be added to basic_ostream, for internal consistency.

A larger question is whether sync should have assigned semantics for input streams.

Classic iostreams said streambuf::sync flushes pending output and attempts to return unread input characters to the source. It is a protected member function. The filebuf version (which is public) has that behavior (it backs up the read pointer). Class strstreambuf does not override streambuf::sync, and so sync can't be called on a strstream.

If we can add corresponding semantics to the various sync functions, we should. If not, we should remove sync from basic_istream.

Rationale:

A sync function is not needed in basic_ostream because the flush function provides the desired functionality.

As for the other points, the LWG finds the standard correct as written.


116. bitset cannot be constructed with a const char*

Section: 23.3.5 [template.bitset] Status: Dup Submitter: Judy Ward Date: 1998-11-06

View all other issues in [template.bitset].

View all issues with Dup status.

Duplicate of: 778

Discussion:

The following code does not compile with the EDG compiler:

#include <bitset>
using namespace std;
bitset<32> b("111111111");

If you cast the ctor argument to a string, i.e.:

bitset<32> b(string("111111111"));

then it will compile. The reason is that bitset has the following templatized constructor:

template <class charT, class traits, class Allocator>
explicit bitset (const basic_string<charT, traits, Allocator>& str, ...);

According to the compiler vendor, Steve Adamcyk at EDG, the user cannot pass this template constructor a const char* and expect a conversion to basic_string. The reason is "When you have a template constructor, it can get used in contexts where type deduction can be done. Type deduction basically comes up with exact matches, not ones involving conversions."

I don't think the intention when this constructor became templatized was for construction from a const char* to no longer work.

Proposed resolution:

Add to 23.3.5 [template.bitset] a bitset constructor declaration

explicit bitset(const char*);

and in Section 23.3.5.1 [bitset.cons] add:

explicit bitset(const char* str);

Effects:
    Calls bitset((string) str, 0, string::npos);

Rationale:

Although the problem is real, the standard is designed that way so it is not a defect. Education is the immediate workaround. A future standard may wish to consider the Proposed Resolution as an extension.


121. Detailed definition for ctype<wchar_t> specialization

Section: 22.1.1.1.1 [locale.category] Status: NAD Submitter: Judy Ward Date: 1998-12-15

View all other issues in [locale.category].

View all issues with NAD status.

Discussion:

Section 22.1.1.1.1 has the following listed in Table 51: ctype<char> , ctype<wchar_t>.

Also Section 22.2.1.1 [locale.ctype] says:

The instantiations required in Table 51 (22.1.1.1.1) namely ctype<char> and ctype<wchar_t> , implement character classing appropriate to the implementation's native character set.

However, Section 22.2.1.3 [facet.ctype.special] only has a detailed description of the ctype<char> specialization, not the ctype<wchar_t> specialization.

Proposed resolution:

Add the ctype<wchar_t> detailed class description to Section 22.2.1.3 [facet.ctype.special].

Rationale:

Specialization for wchar_t is not needed since the default is acceptable.


131. list::splice throws nothing

Section: 23.2.4.4 [list.ops] Status: NAD Submitter: Howard Hinnant Date: 1999-03-06

View all other issues in [list.ops].

View all issues with NAD status.

Discussion:

What happens if a splice operation causes the size() of a list to grow beyond max_size()?

Rationale:

Size() cannot grow beyond max_size(). 


135. basic_iostream doubly initialized

Section: 27.6.1.5.1 [iostream.cons] Status: NAD Submitter: Howard Hinnant Date: 1999-03-06

View all issues with NAD status.

Discussion:

-1- Effects Constructs an object of class basic_iostream, assigning initial values to the base classes by calling basic_istream<charT,traits>(sb) (lib.istream) and basic_ostream<charT,traits>(sb) (lib.ostream)

The called for basic_istream and basic_ostream constructors call init(sb). This means that the basic_iostream's virtual base class is initialized twice.

Proposed resolution:

Change 27.6.1.5.1, paragraph 1 to:

-1- Effects Constructs an object of class basic_iostream, assigning initial values to the base classes by calling basic_istream<charT,traits>(sb) (lib.istream).

Rationale:

The LWG agreed that the init() function is called twice, but said that this is harmless and so not a defect in the standard.


138. Class ctype_byname<char> redundant and misleading

Section: 22.2.1.4 [locale.codecvt] Status: NAD Future Submitter: Angelika Langer Date: 1999-03-18

View all other issues in [locale.codecvt].

View all issues with NAD Future status.

Discussion:

Section 22.2.1.4 [locale.codecvt] specifies that ctype_byname<char> must be a specialization of the ctype_byname template.

It is common practice in the standard that specializations of class templates are only mentioned where the interface of the specialization deviates from the interface of the template that it is a specialization of. Otherwise, the fact whether or not a required instantiation is an actual instantiation or a specialization is left open as an implementation detail.

Clause 22.2.1.4 deviates from that practice and for that reason is misleading. The fact, that ctype_byname<char> is specified as a specialization suggests that there must be something "special" about it, but it has the exact same interface as the ctype_byname template. Clause 22.2.1.4 does not have any explanatory value, is at best redundant, at worst misleading - unless I am missing anything.

Naturally, an implementation will most likely implement ctype_byname<char> as a specialization, because the base class ctype<char> is a specialization with an interface different from the ctype template, but that's an implementation detail and need not be mentioned in the standard.

Rationale:

The standard as written is mildly misleading, but the correct fix is to deal with the underlying problem in the ctype_byname base class, not in the specialization. See issue 228.


140. map<Key, T>::value_type does not satisfy the assignable requirement

Section: 23.3.1 [map] Status: NAD Editorial Submitter: Mark Mitchell Date: 1999-04-14

View all other issues in [map].

View all issues with NAD Editorial status.

Discussion:

23.1 [container.requirements]

expression         return type      pre/post-condition
-------------     -----------      -------------------
X::value_type    T                    T is assignable

23.3.1 [map]

A map satisfies all the requirements of a container.

For a map<Key, T> ... the value_type is pair<const Key, T>.

There's a contradiction here. In particular, `pair<const Key, T>' is not assignable; the `const Key' cannot be assigned to. So,  map<Key, T>::value_type does not satisfy the assignable requirement imposed by a container.

[See issue 103 for the slightly related issue of modification of set keys.]

Rationale:

The LWG believes that the standard is inconsistent, but that this is a design problem rather than a strict defect. May wish to reconsider for the next standard.


143. C .h header wording unclear

Section: D.5 [depr.c.headers] Status: NAD Submitter: Christophe de Dinechin Date: 1999-05-04

View all issues with NAD status.

Discussion:

[depr.c.headers] paragraph 2 reads:

Each C header, whose name has the form name.h, behaves as if each name placed in the Standard library namespace by the corresponding cname header is also placed within the namespace scope of the namespace std and is followed by an explicit using-declaration (_namespace.udecl_)

I think it should mention the global name space somewhere...  Currently, it indicates that name placed in std is also placed in std...

I don't know what is the correct wording. For instance, if struct tm is defined in time.h, ctime declares std::tm. However, the current wording seems ambiguous regarding which of the following would occur for use of both ctime and time.h:

// version 1:
namespace std {
        struct tm { ... };
}
using std::tm;

// version 2:
struct tm { ... };
namespace std {
        using ::tm;
}

// version 3:
struct tm { ... };
namespace std {
        struct tm { ... };
}

I think version 1 is intended.

[Kona: The LWG agreed that the wording is not clear. It also agreed that version 1 is intended, version 2 is not equivalent to version 1, and version 3 is clearly not intended. The example below was constructed by Nathan Myers to illustrate why version 2 is not equivalent to version 1.

Although not equivalent, the LWG is unsure if (2) is enough of a problem to be prohibited. Points discussed in favor of allowing (2):

]

Example:

#include <time.h>
#include <utility>

int main() {
    std::tm * t;
    make_pair( t, t ); // okay with version 1 due to Koenig lookup
                       // fails with version 2; make_pair not found
    return 0;
}

Proposed resolution:

Replace D.5 [depr.c.headers] paragraph 2 with:

Each C header, whose name has the form name.h, behaves as if each name placed in the Standard library namespace by the corresponding cname header is also placed within the namespace scope of the namespace std by name.h and is followed by an explicit using-declaration (_namespace.udecl_) in global scope.

Rationale:

The current wording in the standard is the result of a difficult compromise that averted delay of the standard. Based on discussions in Tokyo it is clear that there is no still no consensus on stricter wording, so the issue has been closed. It is suggested that users not write code that depends on Koenig lookup of C library functions.


145. adjustfield lacks default value

Section: 27.4.4.1 [basic.ios.cons] Status: NAD Submitter: Angelika Langer Date: 1999-05-12

View all other issues in [basic.ios.cons].

View all issues with NAD status.

Discussion:

There is no initial value for the adjustfield defined, although many people believe that the default adjustment were right. This is a common misunderstanding. The standard only defines that, if no adjustment is specified, all the predefined inserters must add fill characters before the actual value, which is "as if" the right flag were set. The flag itself need not be set.

When you implement a user-defined inserter you cannot rely on right being the default setting for the adjustfield. Instead, you must be prepared to find none of the flags set and must keep in mind that in this case you should make your inserter behave "as if" the right flag were set. This is surprising to many people and complicates matters more than necessary.

Unless there is a good reason why the adjustfield should not be initialized I would suggest to give it the default value that everybody expects anyway.

Rationale:

This is not a defect. It is deliberate that the default is no bits set. Consider Arabic or Hebrew, for example. See 22.2.2.2.2 [facet.num.put.virtuals] paragraph 19, Table 61 - Fill padding.


149. Insert should return iterator to first element inserted

Section: 23.1.3 [sequence.reqmts] Status: NAD Future Submitter: Andrew Koenig Date: 1999-06-28

View all other issues in [sequence.reqmts].

View all issues with NAD Future status.

Discussion:

Suppose that c and c1 are sequential containers and i is an iterator that refers to an element of c. Then I can insert a copy of c1's elements into c ahead of element i by executing

c.insert(i, c1.begin(), c1.end());

If c is a vector, it is fairly easy for me to find out where the newly inserted elements are, even though i is now invalid:

size_t i_loc = i - c.begin();
c.insert(i, c1.begin(), c1.end());

and now the first inserted element is at c.begin()+i_loc and one past the last is at c.begin()+i_loc+c1.size().

But what if c is a list? I can still find the location of one past the last inserted element, because i is still valid. To find the location of the first inserted element, though, I must execute something like

for (size_t n = c1.size(); n; --n)
   --i;

because i is now no longer a random-access iterator.

Alternatively, I might write something like

bool first = i == c.begin();
list<T>::iterator j = i;
if (!first) --j;
c.insert(i, c1.begin(), c1.end());
if (first)
   j = c.begin();
else
   ++j;

which, although wretched, requires less overhead.

But I think the right solution is to change the definition of insert so that instead of returning void, it returns an iterator that refers to the first element inserted, if any, and otherwise is a copy of its first argument. 

Rationale:

The LWG believes this was an intentional design decision and so is not a defect. It may be worth revisiting for the next standard.


157. Meaningless error handling for pword() and iword()

Section: 27.4.2.5 [ios.base.storage] Status: Dup Submitter: Dietmar Kühl Date: 1999-07-20

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

View all issues with Dup status.

Duplicate of: 41

Discussion:

According to paragraphs 2 and 4 of 27.4.2.5 [ios.base.storage], the functions iword() and pword() "set the badbit (which might throw an exception)" on failure. ... but what does it mean for ios_base to set the badbit? The state facilities of the IOStream library are defined in basic_ios, a derived class! It would be possible to attempt a down cast but then it would be necessary to know the character type used...

Rationale:


162. Really "formatted input functions"?

Section: 27.6.1.2.3 [istream::extractors] Status: Dup Submitter: Dietmar Kühl Date: 1999-07-20

View all other issues in [istream::extractors].

View all issues with Dup status.

Duplicate of: 60

Discussion:

It appears to be somewhat nonsensical to consider the functions defined in the paragraphs 1 to 5 to be "Formatted input function" but since these functions are defined in a section labeled "Formatted input functions" it is unclear to me whether these operators are considered formatted input functions which have to conform to the "common requirements" from 27.6.1.2.1 [istream.formatted.reqmts]: If this is the case, all manipulators, not just ws, would skip whitespace unless noskipws is set (... but setting noskipws using the manipulator syntax would also skip whitespace :-)

See also issue 166 for the same problem in formatted output

Rationale:


163. Return of gcount() after a call to gcount

Section: 27.6.1.3 [istream.unformatted] Status: Dup Submitter: Dietmar Kühl Date: 1999-07-20

View all other issues in [istream.unformatted].

View all issues with Dup status.

Duplicate of: 60

Discussion:

It is not clear which functions are to be considered unformatted input functions. As written, it seems that all functions in 27.6.1.3 [istream.unformatted] are unformatted input functions. However, it does not really make much sense to construct a sentry object for gcount(), sync(), ... Also it is unclear what happens to the gcount() if eg. gcount(), putback(), unget(), or sync() is called: These functions don't extract characters, some of them even "unextract" a character. Should this still be reflected in gcount()? Of course, it could be read as if after a call to gcount() gcount() return 0 (the last unformatted input function, gcount(), didn't extract any character) and after a call to putback() gcount() returns -1 (the last unformatted input function putback() did "extract" back into the stream). Correspondingly for unget(). Is this what is intended? If so, this should be clarified. Otherwise, a corresponding clarification should be used.

Rationale:


166. Really "formatted output functions"?

Section: 27.6.2.6.3 [ostream.inserters] Status: Dup Submitter: Dietmar Kühl Date: 1999-07-20

View all issues with Dup status.

Duplicate of: 60

Discussion:

From 27.6.2.6.1 [ostream.formatted.reqmts] it appears that all the functions defined in 27.6.2.6.3 [ostream.inserters] have to construct a sentry object. Is this really intended?

This is basically the same problem as issue 162 but for output instead of input.

Rationale:


177. Complex operators cannot be explicitly instantiated

Section: 26.3.6 [complex.ops] Status: NAD Submitter: Judy Ward Date: 1999-07-02

View all other issues in [complex.ops].

View all issues with NAD status.

Discussion:

A user who tries to explicitly instantiate a complex non-member operator will get compilation errors. Below is a simplified example of the reason why. The problem is that iterator_traits cannot be instantiated on a non-pointer type like float, yet when the compiler is trying to decide which operator+ needs to be instantiated it must instantiate the declaration to figure out the first argument type of a reverse_iterator operator.

namespace std {
template <class Iterator> 
struct iterator_traits
{
    typedef typename Iterator::value_type value_type;
};

template <class T> class reverse_iterator;

// reverse_iterator operator+
template <class T> 
reverse_iterator<T> operator+
(typename iterator_traits<T>::difference_type, const reverse_iterator<T>&);

template <class T> struct complex {};

// complex operator +
template <class T>
complex<T> operator+ (const T& lhs, const complex<T>& rhs) 
{ return complex<T>();} 
}

// request for explicit instantiation
template std::complex<float> std::operator+<float>(const float&, 
     const std::complex<float>&);

See also c++-stdlib reflector messages: lib-6814, 6815, 6816.

Rationale:

Implementors can make minor changes and the example will work. Users are not affected in any case.

According to John Spicer, It is possible to explicitly instantiate these operators using different syntax: change "std::operator+<float>" to "std::operator+".

The proposed resolution of issue 120 is that users will not be able to explicitly instantiate standard library templates. If that resolution is accepted then library implementors will be the only ones that will be affected by this problem, and they must use the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion:

Section 27.3.1 says "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (lib.basic.ios.cons). It doesn't say anything about the the state of clog. So this means that calling cerr.tie() and clog.tie() should return 0 (see Table 89 for ios_base::init effects).

Neither of the popular standard library implementations that I tried does this, they both tie cerr and clog to &cout. I would think that would be what users expect.

Rationale:

The standard is clear as written.

27.3.1/5 says that "After the object cerr is initialized, cerr.flags() & unitbuf is nonzero. Its state is otherwise the same as required for ios_base::init (27.4.4.1)." Table 89 in 27.4.4.1, which gives the postconditions of basic_ios::init(), says that tie() is 0. (Other issues correct ios_base::init to basic_ios::init().)


188. valarray helpers missing augmented assignment operators

Section: 26.5.2.6 [valarray.cassign] Status: NAD Submitter: Gabriel Dos Reis Date: 1999-08-15

View all issues with NAD status.

Discussion:

26.5.2.6 defines augmented assignment operators valarray<T>::op=(const T&), but fails to provide corresponding versions for the helper classes. Thus making the following illegal:

#include <valarray>

int main()
{
std::valarray<double> v(3.14, 1999);

v[99] *= 2.0; // Ok

std::slice s(0, 50, 2);

v[s] *= 2.0; // ERROR
}

I can't understand the intent of that omission. It makes the valarray library less intuitive and less useful.

Rationale:

Although perhaps an unfortunate design decision, the omission is not a defect in the current standard.  A future standard may wish to add the missing operators.


191. Unclear complexity for algorithms such as binary search

Section: 25.3.3 [alg.binary.search] Status: NAD Submitter: Nico Josuttis Date: 1999-10-10

View all other issues in [alg.binary.search].

View all issues with NAD status.

Discussion:

The complexity of binary_search() is stated as "At most log(last-first) + 2 comparisons", which seems to say that the algorithm has logarithmic complexity. However, this algorithms is defined for forward iterators. And for forward iterators, the need to step element-by-element results into linear complexity. But such a statement is missing in the standard. The same applies to lower_bound(), upper_bound(), and equal_range(). 

However, strictly speaking the standard contains no bug here. So this might considered to be a clarification or improvement.

Rationale:

The complexity is expressed in terms of comparisons, and that complexity can be met even if the number of iterators accessed is linear. Paragraph 1 already says exactly what happens to iterators.


192. a.insert(p,t) is inefficient and overconstrained

Section: 23.1.4 [associative.reqmts] Status: NAD Submitter: Ed Brey Date: 1999-06-06

View all other issues in [associative.reqmts].

View all issues with NAD status.

Duplicate of: 233

Discussion:

As defined in 23.1.2, paragraph 7 (table 69), a.insert(p,t) suffers from several problems:

expression return type pre/post-condition complexity
a.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t in containers with unique keys; always inserts t in containers with equivalent keys. always returns the iterator pointing to the element with key equivalent to the key of t . iterator p is a hint pointing to where the insert should start to search. logarithmic in general, but amortized constant if t is inserted right after p .

1. For a container with unique keys, only logarithmic complexity is guaranteed if no element is inserted, even though constant complexity is always possible if p points to an element equivalent to t.

2. For a container with equivalent keys, the amortized constant complexity guarantee is only useful if no key equivalent to t exists in the container. Otherwise, the insertion could occur in one of multiple locations, at least one of which would not be right after p.

3. By guaranteeing amortized constant complexity only when t is inserted after p, it is impossible to guarantee constant complexity if t is inserted at the beginning of the container. Such a problem would not exist if amortized constant complexity was guaranteed if t is inserted before p, since there is always some p immediately before which an insert can take place.

4. For a container with equivalent keys, p does not allow specification of where to insert the element, but rather only acts as a hint for improving performance. This negates the added functionality that p would provide if it specified where within a sequence of equivalent keys the insertion should occur. Specifying the insert location provides more control to the user, while providing no disadvantage to the container implementation.

Proposed resolution:

In 23.1.4 [associative.reqmts] paragraph 7, replace the row in table 69 for a.insert(p,t) with the following two rows:

expression return type pre/post-condition complexity
a_uniq.insert(p,t) iterator inserts t if and only if there is no element with key equivalent to the key of t. returns the iterator pointing to the element with key equivalent to the key of t. logarithmic in general, but amortized constant if t is inserted right before p or p points to an element with key equivalent to t.
a_eq.insert(p,t) iterator inserts t and returns the iterator pointing to the newly inserted element. t is inserted right before p if doing so preserves the container ordering. logarithmic in general, but amortized constant if t is inserted right before p.

Rationale:

Too big a change.  Furthermore, implementors report checking both before p and after p, and don't want to change this behavior.


194. rdbuf() functions poorly specified

Section: 27.4.4 [ios] Status: NAD Submitter: Steve Clamage Date: 1999-09-07

View all issues with NAD status.

Discussion:

In classic iostreams, base class ios had an rdbuf function that returned a pointer to the associated streambuf. Each derived class had its own rdbuf function that returned a pointer of a type reflecting the actual type derived from streambuf. Because in ARM C++, virtual function overrides had to have the same return type, rdbuf could not be virtual.

In standard iostreams, we retain the non-virtual rdbuf function design, and in addition have an overloaded rdbuf function that sets the buffer pointer. There is no need for the second function to be virtual nor to be implemented in derived classes.

Minor question: Was there a specific reason not to make the original rdbuf function virtual?

Major problem: Friendly compilers warn about functions in derived classes that hide base-class overloads. Any standard implementation of iostreams will result in such a warning on each of the iostream classes, because of the ill-considered decision to overload rdbuf only in a base class.

In addition, users of the second rdbuf function must use explicit qualification or a cast to call it from derived classes. An explicit qualification or cast to basic_ios would prevent access to any later overriding version if there was one.

What I'd like to do in an implementation is add a using- declaration for the second rdbuf function in each derived class. It would eliminate warnings about hiding functions, and would enable access without using explicit qualification. Such a change I don't think would change the behavior of any valid program, but would allow invalid programs to compile:

 filebuf mybuf;
 fstream f;
 f.rdbuf(mybuf); // should be an error, no visible rdbuf

I'd like to suggest this problem as a defect, with the proposed resolution to require the equivalent of a using-declaration for the rdbuf function that is not replaced in a later derived class. We could discuss whether replacing the function should be allowed.

Rationale:

For historical reasons, the standard is correct as written. There is a subtle difference between the base class rdbuf() and derived class rdbuf(). The derived class rdbuf() always returns the original streambuf, whereas the base class rdbuf() will return the "current streambuf" if that has been changed by the variant you mention.

Permission is not required to add such an extension. See 17.4.4.4 [member.functions].


196. Placement new example has alignment problems

Section: 18.5.1.3 [new.delete.placement] Status: Dup Submitter: Herb Sutter Date: 1998-12-15

View all other issues in [new.delete.placement].

View all issues with Dup status.

Duplicate of: 114

Discussion:

The example in 18.5.1.3 [new.delete.placement] paragraph 4 reads:

[Example: This can be useful for constructing an object at a known address:

   char place[sizeof(Something)];
   Something* p = new (place) Something();

end example]

This example has potential alignment problems.

Rationale:


197. max_size() underspecified

Section: 20.1.2 [allocator.requirements], 23.1 [container.requirements] Status: NAD Submitter: Andy Sawyer Date: 1999-10-21

View other active issues in [allocator.requirements].

View all other issues in [allocator.requirements].

View all issues with NAD status.

Discussion:

Must the value returned by max_size() be unchanged from call to call?

Must the value returned from max_size() be meaningful?

Possible meanings identified in lib-6827:

1) The largest container the implementation can support given "best case" conditions - i.e. assume the run-time platform is "configured to the max", and no overhead from the program itself. This may possibly be determined at the point the library is written, but certainly no later than compile time.

2) The largest container the program could create, given "best case" conditions - i.e. same platform assumptions as (1), but take into account any overhead for executing the program itself. (or, roughly "storage=storage-sizeof(program)"). This does NOT include any resource allocated by the program. This may (or may not) be determinable at compile time.

3) The largest container the current execution of the program could create, given knowledge of the actual run-time platform, but again, not taking into account any currently allocated resource. This is probably best determined at program start-up.

4) The largest container the current execution program could create at the point max_size() is called (or more correctly at the point max_size() returns :-), given it's current environment (i.e. taking into account the actual currently available resources). This, obviously, has to be determined dynamically each time max_size() is called.

Proposed resolution:

Rationale:

max_size() isn't useful for very many things, and the existing wording is sufficiently clear for the few cases that max_size() can be used for. None of the attempts to change the existing wording were an improvement.

It is clear to the LWG that the value returned by max_size() can't change from call to call.


203. basic_istream::sentry::sentry() is uninstantiable with ctype<user-defined type>

Section: 27.6.1.1.3 [istream::sentry] Status: NAD Submitter: Matt McClure and Dietmar Kühl Date: 2000-01-01

View all other issues in [istream::sentry].

View all issues with NAD status.

Discussion:

27.6.1.1.2 Paragraph 4 states:

To decide if the character c is a whitespace character, the constructor performs ''as if'' it executes the following code fragment: 

const ctype<charT>& ctype = use_facet<ctype<charT> >(is.getloc());
if (ctype.is(ctype.space,c)!=0)
// c is a whitespace character.

But Table 51 in 22.1.1.1.1 only requires an implementation to provide specializations for ctype<char> and ctype<wchar_t>. If sentry's constructor is implemented using ctype, it will be uninstantiable for a user-defined character type charT, unless the implementation has provided non-working the indicated syntax.


178. Should clog and cerr initially be tied to cout?

Section: 27.3.1 [narrow.stream.objects] Status: NAD Submitter: Judy Ward Date: 1999-07-02

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

View all issues with NAD status.

Discussion: