On Mon, Oct 18, 2010 at 9:24 PM, Rao, Anant <Anant.Rao@ironmountain.com> wrote:


Hi,

 

I need to iterate thru strings (For various reasons, I can’t use string or vector<char> containers).

I found that boost::range exactly fits the bill for me. I get all the convenience of an iterator (from as_literal.hpp).

 

I have a piece of code

 

char*      char_s = "I am fine";

char *cp;

 

std::size_t sz = strlen(char_s);

const char* str_end1 = str_begin( char_s ) + sz;

 

for (cp = str_begin(char_s); cp != str_end(char_s); ++cp)

    cout << *cp;

 

I have couple of questions:

 

1.       In the loop, boost::range seems to be calling strlen every iteration. This is an overhead. I was wondering if there’s a way I can pass in the length myself so that boost::range would use it and avoid calling strlen().

Indeed in the code snippet provided it would be called every iteration. Since you could simply store the end and compare of course.

However the issue is a little artifical because you would normally have an algorithm which you which to apply to a range. In your example, your algorithm is simply to stream each character. This can be achieved by a number of different approaches.

The most direct standard approach is:
std::cout << char_s;

The most direct range-based approach available in boost 1.43 and greater is:

#include <ostream>
#include <boost/range.hpp>
#include <boost/range/algorithm/copy.hpp>
...
boost::copy( boost::as_literal(char_s), std::ostream_iterator<char>(std::cout) );
 
This example better demonstrates the reason why the re-evaluation of strlen does not occur in practice. The as_literal function evaluates strlen once to obtain the end iterator. The first and last iterators are stored in a range which is then passed into another algorithm, in this case boost::copy. When the boost::range is queried for the end it is a constant-time operation, hence strlen is not re-evaluated.

2.       If it’s not possible, is there a way for me to use iterators (boost or non-boost) over char strings?


It is possible to use iterators over char strings. This does not require Boost.Range or even Boost. The C++ standard carefully designed iterators such that pointers are models of the Random Access Iterator Concept. Hence you can do this:

#include <algorithm>
#include <iostream>

const char* char_s = "abcd";
std::copy( char_s, char_s + strlen(char_s), std::ostream_iterator<int>(std::cout) );
 

Thanks so much in advance for your help,

Anant

I hope this answers your question satisfactorily. Are you avoiding string and vector<char> to eliminate heap operations for small strings? Decent implementations of string with the small buffer optimization are fast enough for almost all purposes. Otherwise it might be worth implementing or using a fixed string. I would like to stress though that the final container type of a Boost.Range idiomatic design would be unimportant to the algorithm. The algorithm would merely deal in models of the Range Concepts, please see http://www.boost.org/doc/libs/1_44_0/libs/range/doc/html/range/concepts.html.

The power of this separation is exemplified by your example. If you decide to implement a new fixed string class you would still be able to utilise the string algorithms within Boost.Algorithm despite these never having been designed for use with your new class.

Best wishes,
Neil Groves