Re: Problem with std::string::npos in CINT

From: Christian Holm Christensen <cholm_at_nbi.dk>
Date: Thu, 21 Sep 2006 02:33:12 +0200


Hi Tobi,

On Wed, 2006-09-20 at 12:23 -0500, Tobias Raufer wrote:
> Hi RootTalk,
>
> I am using version 5.11/02 built from source on a Suse 10 system.
>
> I seem to have a problem when using STL strings in CINT. Consider the
> following short macro:

...
> string testString = "Hello";
> cout << "Find x: " << testString.find("x") << endl;
> cout << "string::npos: " << string::npos << endl;
...
> root [0] .x test.C
> Find x: 4294967295
> string::npos: -1
> root [1]

Believe it or not, but 4294967295 and -1 are the same :) If you do

        > root -l
        root [0] #include <string>
        root [1] std::string s("foo")
        root [2] std::string::npos
        (const enum string::)(-1)
        root [3] s.find("bla")
        (const unsigned int)4294967295
        root [4] int(s.find("bla"))
        (const int)(-1)
        root [5] s.find("bla") == std::string::npos
        (const unsigned int)1
        root [6] s.find("foo") == std::string::npos
        (const unsigned int)0
        unsigned(std::string::npos)
        (const unsigned int)4294967295
        

you will see why. 4294967295 is overflow of an unsigned (32bit) integer. Hence, the implicit promotion the return value of std::string::find to an signed integer (or is it std::string::npos that's demoted to an unsigned integer?) makes the comparison work.

The standard actually specifies npos as (section 21.3, clause 6)

        template <class charT, class traits=char_traits<charT>,
                  Allocator=allocator<charT> >
        class basic_string
        {
           ...
           typedef typename Allocator::size_type size_type;
           ...
           static const size_type npos = -1;
           ...
         };
        

Hence, `-1' is _the_ value of npos (appropriately casted), while `size_type' is defined by the third template parameter. You could imagine a passing an argument like

   class CharAllocator
   {

      ...
      typedef float size_type;
      ...

    };

even though it doesn't make much sense (and could be disallowed by other uses of size_type). However, the assignment `npos = -1' is still valid, as long as the long int value -1 can be converted to size_type.

> Is there a problem with string::npos in CINT?

Nope. The arch-typical usage of npos is something like

        std::string s("foo");
        std::string::size_type i = s.find("bar");
        if (i == std::string::npos) {
           std::cerr << "Argh!, \"bar\" not found in \"" << s << "\"" << std::endl;
           exit(1);
        }
        

And that's really the only way to use `npos'.

> When I compile the same
> macro with ACliC, everything works fine.

Your script _does_ work, even in interpreted mode. The output is perfectly legitimate according to the standard. Note, that the implementation of C++ is pretty free to choose these things (what type is size_type exactly?), and there's nothing wrong in CINT using a different allocator for strings made in the interpreter - in fact, it's probably a very good idea.

Yours,

-- 
 ___  |  Christian Holm Christensen 
  |_| |  -------------------------------------------------------------
    | |  Address: Sankt Hansgade 23, 1. th.  Phone:  (+45) 35 35 96 91
     _|           DK-2200 Copenhagen N       Cell:   (+45) 24 61 85 91
    _|            Denmark                    Office: (+45) 353  25 404
 ____|   Email:   cholm_at_nbi.dk               Web:    www.nbi.dk/~cholm
 | |
Received on Thu Sep 21 2006 - 02:33:32 MEST

This archive was generated by hypermail 2.2.0 : Mon Jan 01 2007 - 16:32:01 MET