This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PR 8347 revisited


Hello.  I mailed Paolo about some issues related to PR 8347 (failing
to construct std::string from an empty vector's begin/end), and they
led me to question the current logic that throws the "attempt to
create a string from null pointer" exception.

The current code for string's iterator-based constructor starts with
the following code:

basic_string(_InputIter __beg, _InputIter __end, const _Alloc& __a)
{
  // ...      

  if (__beg == __end && __a == _Alloc())
    return _S_empty_rep()._M_refcopy();

  // NB: Not required, but considered best practice.
  if (__builtin_expect(__beg == _InIter(), 0))
    __throw_logic_error("attempt to create string with null pointer");

I am worried that the __beg == _InIter()  is invalid invalid for
iterators that are non-pointer types.  It implies that 
default-constructed iterators are non-dereferencable.  My reading of
24.1 paragraph 5 seems to indicate that an _uninitialized_ iterator is
singular and thus not dereferencable.  However, it does not say
whether or not a default-constructed iterator is singular.  In 24.1.3
(table 74, "Forward iterator requirements"), there is a note that says
"X() might be singular", but it does not say that it _must_ be
singular. 

I think that, barring some way to specialize it for pointers alone,
the entire check-and-throw statement might need to be removed.  If
nothing else, the text of the exception is incorrect because __beg
might not be a pointer. 

In other words, I don't think the standard prevents me from writing a
class that meets all the iterator requirements but whose
default-constructed instance _is_ dereferencable.  In such a case,
perhaps the container is implicit; perhaps the iterator runs against
some system resource.

A separate issue that is only relevant if my suspicions are wrong is
that I believe there needs to be an additional check before the
exception can be thrown.  Consider the case where __beg == __end, but
the string is being constructed with a different instance of the
allocator (i.e. __a != _Alloc()).  Because of this, I think the
exception condition (if valid) would have to be:

  if (__beg == __end && __a == _Alloc())
    return _S_empty_rep()._M_refcopy();

  // NB: Not required, but considered best practice.
  if (__builtin_expect(__beg == _InIter(), 0))
    if (__builtin_expect(!(__beg == __end), 0))
      __throw_logic_error("attempt to create string with null pointer

        
-- 
------------------------------------------------------------------
Brad Spencer - spencer@infointeractive.com - "It's quite nice..."
Systems Architect | InfoInterActive Corp. | A Canadian AOL Company


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]