Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a standard C++ iterator for C strings?

Sometimes I need to pass a C string to a function using the common C++ iterator range interface [first, last). Is there a standard C++ iterator class for those cases, or a standard way of doing it without having to copy the string or call strlen()?

EDIT: I know I can use a pointer as an iterator, but I would have to know where the string ends, what would require me to call strlen().

EDIT2: While I didn't know if such iterator is standardized, I certainly know it is possible. Responding to the sarcastic answers and comments, this is the stub (incomplete, untested):

class CStringIterator
{
public:
    CStringIterator(char *str=nullptr):
        ptr(str)
    {}

    bool operator==(const CStringIterator& other) const
    {
        if(other.ptr) {
            return ptr == other.ptr;
        } else {
            return !*ptr;
        }
    }

    /* ... operator++ and other iterator stuff */

private:
    char *ptr;
};

EDIT3: Specifically, I am interested in a forward iterator, because I want to avoid to iterate over the sring twice, when I know the algorithm will only have to do it once.

like image 994
lvella Avatar asked Aug 09 '18 15:08

lvella


2 Answers

There isn't any explicit iterator class, but regular raw pointers are valid iterators as well. Problem with C-strings, though, is that they do not come with a native end iterator, which makes them unusable in range based for loops – directly at least...

You might like to try the following template, though:

template <typename T>
class Range
{
    T* b;
public:
    class Sentinel
    {
        friend class Range;
        Sentinel() { }
        friend bool operator!=(T* t, Sentinel) { return *t; }

    public:
        Sentinel(Sentinel const& o) { }

    };
    Range(T* begin)
            : b(begin)
    { }
    T* begin() { return b; }
    Sentinel end() { return Sentinel(); }
};

Usage:

for(auto c : Range<char const>("hello world"))
{
    std::cout << c << std::endl;
}

It originally was designed to iterate over null-terminated argv of main, but works with any pointer to null terminated array – which a C-string is as well...

Secret is comparing against the sentinel, which actually does a totally different comparison (current pointer pointing the terminating null (pointer))...

Edit: Pre-C++17 variant:

template <typename T>
class Range
{
    T* b;
public:
    class Wrapper
    {
        friend class Range;
        T* t;
        Wrapper(T* t) : t(t) { }
    public:
        Wrapper(Wrapper const& o) : t(o.t) { }
        Wrapper operator++() { ++t; return *this; }
        bool operator!=(Wrapper const& o) const { return *t; }
        T operator*() { return *t; }
    };
    Range(T* begin)
            : b(begin)
    { }
    Wrapper begin() { return Wrapper(b); }
    Wrapper end() { return Wrapper(nullptr); }
};
like image 158
Aconcagua Avatar answered Oct 26 '22 23:10

Aconcagua


Actually, yes - sort of. In c++17.

C++17 introduces std::string_view which can be constructed from a c-style string.

std::string_view is a random access (proxy) container which of course fully supports iterators.

Note that although constructing a string_view from a const char* will theoretically call std::strlen, the compiler is allowed to (and gcc certainly does) elide the call when it knows the length of the string at compile time.

Example:

#include <string_view>
#include <iostream>

template<class Pointer>
struct pointer_span
{
    using iterator = Pointer;

    pointer_span(iterator first, std::size_t size)
    : begin_(first)
    , end_(first + size)
    {
    }

    iterator begin() const { return begin_; }
    iterator end() const { return end_; }

    iterator begin_, end_;
};

int main(int argc, char** argv)
{
    for(auto&& ztr : pointer_span(argv, argc))
    {
        const char* sep = "";
        for (auto ch : std::string_view(ztr))
        {
            std::cout << sep << ch;
            sep = " ";
        }
        std::cout << std::endl;
    }
}

See the example output here

like image 43
Richard Hodges Avatar answered Oct 26 '22 23:10

Richard Hodges