Topic: Suggestion for STL iterators over arrays


Author: Alan Stokes <alan@rcp.co.uk>
Date: 1997/01/30
Raw View
One of the nice things about the STL iterator system is that since
normal pointers satisfy the requirements for random access iterators,
the STL algorithms can be used with normal arrays as well as with the
various container classes. However I think there is a way this could be
made slightly easier.

Given a container C it is easy to get iterators for the beginning and
end of the container - C.begin() and C.end(). For a simple array, e.g.

int a[10];

the iterator to the beginning of the array is easy - it's just a.

The iterator to the end of the array is more complex, &a[10] (or a +
10). The problem with both of these is they are slightly non-obvious,
and require the dimension of the array to be mentioned again.

A better alternative would be to use &a[sizeof(a)/sizeof(*a)], but this
is rather cumbersome.

How about adding to the standard library a function, called array_end
for the sake of argument, that is passed an array name and returns a
pointer to the element one beyond the end of the array? For completeness
you could also have an array_begin.

These could be implemented as macros, although this would mean they
wouldn't follow normal scoping rules.

This would allow code like the following:

void f()
{
   vector<int> a;
   int b[100];

   // lots of stuff

   copy(a.begin(), a.end(), ostream_iterator<int>(cout));
   copy(array_begin(b), array_end(b), ostream_iterator<int>(cout));
}

--
Alan Stokes (alan@rcp.co.uk)
RCP Consultants Ltd
Didcot, UK


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: tottinge@oma.com (Tim Ottinger)
Date: 1997/01/31
Raw View
On 30 Jan 1997 16:35:32 GMT, Alan Stokes <alan@rcp.co.uk> wrote:

>How about adding to the standard library a function, called array_end
>for the sake of argument, that is passed an array name and returns a
>pointer to the element one beyond the end of the array? For completeness
>you could also have an array_begin.

Alan: array_begin is easy enough, but there is a real problem with
array_end(). C-style variables (primative/native types) are not at
all self-descriptive.

If you happen to have the declaration of 'a' in view, you can use
sizeof(a) to get the total byte-length of the array, and you can
work that out with the method given.

As likely as not, though, you'll have 'T *a' passed to you, and
you'll need to manipulate the array through the pointer. In this
case, the array_end() would work very poorly (sizeof(T)/sizeof(T*)).
In C, you usually want to maintain the illusion of a pointer being
an array (when handling arrays).

Probably the best way to deal with this is using STL containers
rather than pointers whenever at all possible.  The containers
ARE self-describing and then you can do it the easy way.

If you have control over whether a thing is an array or not, then
by all means use standard containers instead. If someone is passing
you the array (you don't have control) then your idea can't be
made to work.  Sorry.

But it's a nice thought.
-------------------------------------------------------------
Tim Ottinger      | Object Mentor Inc. | OOA/D, C++, more..
tottinge@oma.com  | http://www.oma.com | Training/Consulting
-------------------------------------------------------------
"... remember, there are ways of succeeding that we would not
 personally have chosen. "              - Bjarne Stroustrup
-------------------------------------------------------------
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: kuehl@uzwil.informatik.uni-konstanz.de (Dietmar Kuehl)
Date: 1997/01/31
Raw View
Hi,
Alan Stokes (alan@rcp.co.uk) wrote:
: How about adding to the standard library a function, called array_end
: for the sake of argument, that is passed an array name and returns a
: pointer to the element one beyond the end of the array? For completeness
: you could also have an array_begin.

In general, you have to pass around the size of an array to figure out
it's size and there is such a thingy already in the C++ standard: It is
spelled "vector" :-)  The point is: To make this 'array_end()' function
work, it requires that the size of an array is known at run-time. If an
array is passed to function it is currently passed as a pointer to the
first element, without any information about the size of the array.

Thus, your 'array_end()' function can only work in the enclosing scope
(probably I misuse or make up the term "enclosing scope" here; what I
mean is that you have to be in the function where the array is
declared; correspondingly if the array is declared in the global scope,
as class member, etc.) of the array. The following should work if you
are in the enclosing scope of an array (at least I think it should work
and it does work at with gcc-2.7.2 and KCC-3.1a which is, of course, no
proof that it is standard conforming):

  template <class T, unsigned int size>
  inline unsigned int array_size(T (&a)[size])
  {
    return size;
  }
  template <class T, unsigned int size>
  inline T *array_begin(T (&a)[size])
  {
    return a;
  }
  template <class T, unsigned int size>
  inline T *array_end(T (&a)[size])
  {
    return a + size;
  }

It would be nice if these were already in the standard library (e.g. in
the section for general utilities...) but then, it is not hard to put
them into a header (... and it is probably too late for even such minor
enhancements to the standard library to be considered; maybe in the
next round of standardization). In any case, templates like this are
handy to get values from a built-in array into an STL container: Unlike
built-in arrays, STL containers cannot be initialized with a list of
objects.

Note, however, that there is a catch: The following does not work with
the above functions and I don't think that there is a possibility to
make it work without changing the language:

  int f(int array[3])
  {
    return array_size(array);
  }
  int main()
  {
    int array[] = { 1, 2, 3 };
    return f(array);
  }

That this does not work may come as a surprise since the same statement
as the one in 'f()' applied in 'main()' does work.  Since arrays are
passed as pointers, the '3' is ignored in the above declaration of
'f()'. To make the functions work again, you would have to declare
'f()' as 'int f(int (&array)[3])'.
--
<mailto:dietmar.kuehl@uni-konstanz.de>
<http://www.informatik.uni-konstanz.de/~kuehl/>
I am a realistic optimist - that's why I appear to be slightly pessimistic
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: ken@digitas.harvard.edu (Ken Shan)
Date: 1997/02/03
Raw View
Alan Stokes (alan@rcp.co.uk) wrote:
> How about adding to the standard library a function, called array_end
> for the sake of argument, that is passed an array name and returns a
> pointer to the element one beyond the end of the array? For completeness
> you could also have an array_begin.

Even better...  Define pseudo "member functions" for arrays named
begin() and end(), so that

    int a[10];
    int b[10];
    copy(a.begin(), a.end(), b.begin());

does what I hope it does.

--
blue | Ken; Shan, Chung-chieh; Sian7, Tiong1-kiat8; ken@digitas.harvard.edu.
 ()  | Your code today becomes the mind tomorrow:  Your plan its means,
 /\  | your dream its ends, your ideal its elegance.  Hack on.
==== Course Decision Assistant 2.0: http://www.digitas.harvard.edu/cda/ ====


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: kuehl@uzwil.informatik.uni-konstanz.de (Dietmar Kuehl)
Date: 1997/02/03
Raw View
Hi,
Ken Shan (ken@digitas.harvard.edu) wrote:
: Alan Stokes (alan@rcp.co.uk) wrote:
: > How about adding to the standard library a function, called array_end
: > for the sake of argument, that is passed an array name and returns a
: > pointer to the element one beyond the end of the array? For completeness
: > you could also have an array_begin.

: Even better...  Define pseudo "member functions" for arrays named
: begin() and end(), so that

No, I don't think that would be better! Built-in arrays are a quite low
level construction whose use is quite error prone. The use of this
construct should be limited to cases where it is absolutely necessary
and it should, IMO, not used outside these limited cases. Adding some
neat syntax to make the use of this low level construct more convenient
is the wrong signal.

I can think only of few legatimate uses of built-in arrays

- For the implementation of array classes like 'vector' or 'deque'. The
  addition of the 'begin()'/'end()' notation would help only in very
  few cases here, since most of the arrays used are dynamically
  allocated such that 'end()' would not be implementable without giving
  up some optimization. Only where the size of the used array is known
  at compile time (e.g. in 'bitset'), this would help and there the
  solution to the second case also works.

- Unfortunately, there is no way to initialize a user defined container
  class from a list of object like it is possible for built-in arrays.
  Thus, I think that a sequence like
    T tarray[] = { T1, ..., Tn };
    copy(tarray, array_end(tarray), dest);
  where 'dest' is some output iterator and 'array_end()' is a function
  defined as
    template <class T, unsigned int size>
    T *array_end(T (&array)[size]) { return array + size; }
  is another legitmate use of built-in arrays. However, the only
  frequent use for initialized built-in arrays I had, was sample code,
  e.g. for STL algorithms...

- String literals can be seen as a use of built-in arrays. However, the
  only use of string literals is to construct an object of some class,
  like 'string' or 'ofstream'.

Beyond these uses, there are only very rare cases where I can imagine
an appropriate use of built-in arrays. Since all uses already have a
reasonable solution, I don't think that the core language should be
changed in this respect. Whether template functions like 'array_end()'
and 'array_size()', maybe for completeness 'array_begin(), too, should
be added to the standard C++ library is a different issue...
--
<mailto:dietmar.kuehl@uni-konstanz.de>
<http://www.informatik.uni-konstanz.de/~kuehl/>
I am a realistic optimist - that's why I appear to be slightly pessimistic


[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]