Passing a vector to a function expecting an array

A

alamaison

Hi all,

As rarely seen but variously recommended (see C++ Coding Standards,
Sutter and Alexandrescu for example) I'm trying to pass a vector of
items to a function that expects an array. The tricky part is that
the function expects the array to be passed half-open (pointer to a
[0], pointer to one-past-end) rather that &a[0] and a size. This
means that I'm trying to do the following:

vector<item> files;
....fill vector...
pobject->Init(&files[0], &files[0] + files.size(), ...);

This works fine unless the vector happens to be empty which, given
that this function initialises a type of domain-specific collection,
is perfectly reasonable. &files[0] triggers the STL debugging with an
out-of-bounds error. The Init function itself has no problem with the
situation. If it receives two identical pointers it simple creates an
empty collection.

Now, obviously, I can hack around this problem by passing Init a
pointer to anything twice if files.empty() but I would like to know
the 'proper' C++ way to do this. Can it be done gracefully?

Many thanks.

Alex Lamaison

-- http://swish.sourceforge.net
 
P

peter koch

Hi all,

As rarely seen but variously recommended (see C++ Coding Standards,
Sutter and Alexandrescu for example) I'm trying to pass a vector of
items to a function that expects an array.  The tricky part is that
the function expects the array to be passed half-open (pointer to a
[0], pointer to one-past-end) rather that &a[0] and a size.  This
means that I'm trying to do the following:

vector<item> files;
...fill vector...
pobject->Init(&files[0], &files[0] + files.size(), ...);

This works fine unless the vector happens to be empty which, given
that this function initialises a type of domain-specific collection,
is perfectly reasonable.  &files[0] triggers the STL debugging with an
out-of-bounds error.  The Init function itself has no problem with the
situation.  If it receives two identical pointers it simple creates an
empty collection.

Now, obviously, I can hack around this problem by passing Init a
pointer to anything twice if files.empty() but I would like to know
the 'proper' C++ way to do this.  Can it be done gracefully?

Use a function that returns a pointer to the first element of a vector
or 0 if the vector is empty.
This makes your function look like
pobject->Init(dataof(files), dataof(files) + files.size(), ...);

Which is not to bad (and not to far away from the C++0x solution
pobject->Init(files.data(), files.data() + files.size(), ...) if my
memory serves me)

/Peter
 
G

Gerhard Fiedler

Hi all,

As rarely seen but variously recommended (see C++ Coding Standards,
Sutter and Alexandrescu for example) I'm trying to pass a vector of
items to a function that expects an array.  The tricky part is that
the function expects the array to be passed half-open (pointer to a
[0], pointer to one-past-end) rather that &a[0] and a size.  This
means that I'm trying to do the following:

vector<item> files;
...fill vector...
pobject->Init(&files[0], &files[0] + files.size(), ...);

This works fine unless the vector happens to be empty which, given
that this function initialises a type of domain-specific collection,
is perfectly reasonable.  &files[0] triggers the STL debugging with an
out-of-bounds error.  The Init function itself has no problem with the
situation.  If it receives two identical pointers it simple creates an
empty collection.

Now, obviously, I can hack around this problem by passing Init a
pointer to anything twice if files.empty() but I would like to know
the 'proper' C++ way to do this.  Can it be done gracefully?

Use a function that returns a pointer to the first element of a vector
or 0 if the vector is empty.
This makes your function look like
pobject->Init(dataof(files), dataof(files) + files.size(), ...);

Which is not to bad (and not to far away from the C++0x solution
pobject->Init(files.data(), files.data() + files.size(), ...) if my
memory serves me)

Or subclass the vector and add a data() function (that does the same
thing)?

Gerhard
 
A

alamaison

The tricky part is that
the function expects the array to be passed half-open (pointer to a
[0], pointer to one-past-end) rather that &a[0] and a size.  This
means that I'm trying to do the following:
vector<item> files;
...fill vector...
pobject->Init(&files[0], &files[0] + files.size(), ...); ....
The Init function itself has no problem with the
situation.  If it receives two identical pointers it simple creates an
empty collection.

Use a function that returns a pointer to the first element of a vector
or 0 if the vector is empty.
This makes your function look like
pobject->Init(dataof(files), dataof(files) + files.size(), ...);

Which is not to bad (and not to far away from the C++0x solution
pobject->Init(files.data(), files.data() + files.size(), ...) if my
memory serves me)

Thanks for the answers, guys.

Interesting. So was data() introduced to address exactly this
concern? Unfortunately this still won't work for me as the collection
thinks it hasn't been initialised if either of its members, which are
set to the value of these two pointers, is NULL. I suppose the 'array
way' of looking at it is that one-past-the-end is always a valid
address to reference (at least according to the _C_ standard) and so
&files[0] should be ok even for an empty array. What I need is a way
to get this value without the debugger catching it as an error.
 
N

Noah Roberts

alamaison said:
I suppose the 'array
way' of looking at it is that one-past-the-end is always a valid
address to reference (at least according to the _C_ standard) and so
&files[0] should be ok even for an empty array.

No, no.

It is always valid to look at the address of the area one past the end
of an array. You can compare the value of this *address* to other
values and this behavior is defined. It is NEVER valid to dereference
that address, which is what array notation does.

files[0] == *(files + 0)

Thus you've caused undefined behavior before taking the address.
 
A

alamaison

vector said:
...fill vector...
pobject->Init(&files[0], &files[0] + files.size(), ...);
Use a function that returns a pointer to the first element of a vector
or 0 if the vector is empty.
This makes your function look like
pobject->Init(dataof(files), dataof(files) + files.size(), ...);
Unfortunately this still won't work for me as the collection
thinks it hasn't been initialised if either of its members, which are
set to the value of these two pointers, is NULL.  I suppose the 'array
way' of looking at it is that one-past-the-end is always a valid
address to reference (at least according to the _C_ standard) and so
&files[0] should be OK even for an empty array.  What I need is a way
to get this value without the debugger catching it as an error.

You can't. There might be no array allocated at all for zero element
case, thus you cannot form a pointer past the end of it. The best you can
do is to check for zero size and substitute some valid pointer, like
NULL.

So, &files[0] is UB even if the result is not used. MS has decided to
define this UB as runtime crash if checked iterators are used.
Ironically, without this check the code would most likely not crash
because in Win32 flat memory model all bit patterns constitute valid
pointers unless dereferenced. So it appears MS is now helping here to
keep the code more portable, a rare occasion ;-) You should take the
advice and fix the code.

It is always valid to look at the address of the area one past the end
of an array. You can compare the value of this *address* to other
values and this behavior is defined. It is NEVER valid to dereference
that address, which is what array notation does.

files[0] == *(files + 0)

Thus you've caused undefined behavior before taking the address.

Thanks to both of you for pitching in.

I think I may have been unclear in what I was trying to say. I
understand _why_ the checked STL catches &files[0]. All I'm trying to
say is that it doesn't match with how plain-old C arrays work. Just
as Noah says, with arrays you can use the _address_ of one-past-the-
end as a marker (that's what I meant by reference - not a good choice
of term). This is the one and only out-of-bounds address that is
legal to use according to the C standard; possibly this is different
for C++. Of course, you can't dereference this address, neither do I
want to.

Vector is touted as a complete replacement for arrays when passing
arguments to legacy code but I'm not sure it quite measures up if it
can't be used in this way.

Comments most welcome.

Alex
 
P

peter koch

[snip]
It is always valid to look at the address of the area one past the end
of an array.  You can compare the value of this *address* to other
values and this behavior is defined.  It is NEVER valid to dereference
that address, which is what array notation does.
files[0] == *(files + 0)
Thus you've caused undefined behavior before taking the address.

Thanks to both of you for pitching in.

I think I may have been unclear in what I was trying to say.  I
understand _why_ the checked STL catches &files[0].  All I'm trying to
say is that it doesn't match with how plain-old C arrays work.  

Well... C-arrays can't be empty, so the analogy breaks down a bit.
Just
as Noah says, with arrays you can use the _address_ of one-past-the-
end as a marker (that's what I meant by reference - not a good choice
of term).  This is the one and only out-of-bounds address that is
legal to use according to the C standard; possibly this is different
for C++.  Of course, you can't dereference this address, neither do I
want to.

Vector is touted as a complete replacement for arrays when passing
arguments to legacy code but I'm not sure it quite measures up if it
can't be used in this way.

It can. As advised in another post, you can pass e.g. 0 if there are
no elements in the vector. So you write e.g. x.empty? 0: &x[0] instead
of &x[0], or you write a function if you find that to be more
readable. It is only four lines fully templated, so it really is no
big deal.
C++0x has these four lines ready for you, but they are not part of C+
+98 as originally there was no requirement that std::vector should be
able to replace built-in arrays.

/Peter
 
P

peter koch

Hi all,
As rarely seen but variously recommended (see C++ Coding Standards,
Sutter and Alexandrescu for example) I'm trying to pass a vector of
items to a function that expects an array.  The tricky part is that
the function expects the array to be passed half-open (pointer to a
[0], pointer to one-past-end) rather that &a[0] and a size.  This
means that I'm trying to do the following:
vector<item> files;
...fill vector...
pobject->Init(&files[0], &files[0] + files.size(), ...);
This works fine unless the vector happens to be empty which, given
that this function initialises a type of domain-specific collection,
is perfectly reasonable.  &files[0] triggers the STL debugging with an
out-of-bounds error.  The Init function itself has no problem with the
situation.  If it receives two identical pointers it simple creates an
empty collection.
Now, obviously, I can hack around this problem by passing Init a
pointer to anything twice if files.empty() but I would like to know
the 'proper' C++ way to do this.  Can it be done gracefully?
Use a function that returns a pointer to the first element of a vector
or 0 if the vector is empty.
This makes your function look like
pobject->Init(dataof(files), dataof(files) + files.size(), ...);
Which is not to bad (and not to far away from the C++0x solution
pobject->Init(files.data(), files.data() + files.size(), ...) if my
memory serves me)

Or subclass the vector and add a data() function (that does the same
thing)?

This is a very bad idea: for one thing, you will not be able to
support code that has already been written, and even if you rewrote
that code, there would still be the problem with third-party
libraries.

/Peter
 
A

alamaison

Well... C-arrays can't be empty, so the analogy breaks down a bit.

True. I may be stretching the analogy too far.
Vector is touted as a complete replacement for arrays when passing
arguments to legacy code but I'm not sure it quite measures up if it
can't be used in this way.

It can. As advised in another post, you can pass e.g. 0 if there are
no elements in the vector. So you write e.g. x.empty? 0: &x[0] instead
of &x[0], or you write a function if you find that to be more
readable. It is only four lines fully templated, so it really is no
big deal.
C++0x has these four lines ready for you, but they are not part of C+
+98 as originally there was no requirement that std::vector should be
able to replace built-in arrays.

This does seem like a pretty good solution for the general case and I
will use it from now on. Unfortunately it doesn't work in this
specific instance but I never really cared about that anyway. More
interested in the principle of it.
 
G

Gerhard Fiedler

As rarely seen but variously recommended (see C++ Coding Standards,
Sutter and Alexandrescu for example) I'm trying to pass a vector
of items to a function that expects an array.  The tricky part is
that the function expects the array to be passed half-open
(pointer to a [0], pointer to one-past-end) rather that &a[0] and
a size.  This means that I'm trying to do the following:
vector<item> files;
...fill vector...
pobject->Init(&files[0], &files[0] + files.size(), ...);
This works fine unless the vector happens to be empty which, given
that this function initialises a type of domain-specific
collection, is perfectly reasonable.  &files[0] triggers the STL
debugging with an out-of-bounds error.  The Init function itself
has no problem with the situation.  If it receives two identical
pointers it simple creates an empty collection.
Now, obviously, I can hack around this problem by passing Init a
pointer to anything twice if files.empty() but I would like to
know the 'proper' C++ way to do this.  Can it be done gracefully?
Use a function that returns a pointer to the first element of a vector
or 0 if the vector is empty.
This makes your function look like
pobject->Init(dataof(files), dataof(files) + files.size(), ...);
Which is not to bad (and not to far away from the C++0x solution
pobject->Init(files.data(), files.data() + files.size(), ...) if my
memory serves me)

Or subclass the vector and add a data() function (that does the same
thing)?

This is a very bad idea: for one thing, you will not be able to
support code that has already been written, and even if you rewrote
that code, there would still be the problem with third-party
libraries.

??

The existing code expects a pointer to the first and a pointer past the
last element. The code that has to interface to this code is being
written. This subclass is for code that is currently being written. If
you receive from some other code a vector that is to be passed to that
function, you can always cast it to the subclass.

Can you please construct a not too constructed situation that is
compatible with the situation as outlined above where subclassing would
be a problem?

Gerhard
 
G

Gerhard Fiedler

Unfortunately this still won't work for me as the collection thinks it
hasn't been initialised if either of its members, which are set to
the value of these two pointers, is NULL.

You don't have to use NULL as address if the size of the array is 0. You
should be able to use any address -- supposedly that function doesn't do
any dereferencing in this case, just comparing with NULL and some
pointer arithmetic. Instead of (x.empty()? 0: &x[0]) you can use
(x.empty()? &x: &x[0]), for example.

Gerhard
 
P

peter koch

As rarely seen but variously recommended (see C++ Coding Standards,
Sutter and Alexandrescu for example) I'm trying to pass a vector
of items to a function that expects an array.  The tricky part is
that the function expects the array to be passed half-open
(pointer to a [0], pointer to one-past-end) rather that &a[0] and
a size.  This means that I'm trying to do the following:
vector<item> files;
...fill vector...
pobject->Init(&files[0], &files[0] + files.size(), ...);
This works fine unless the vector happens to be empty which, given
that this function initialises a type of domain-specific
collection, is perfectly reasonable.  &files[0] triggers the STL
debugging with an out-of-bounds error.  The Init function itself
has no problem with the situation.  If it receives two identical
pointers it simple creates an empty collection.
Now, obviously, I can hack around this problem by passing Init a
pointer to anything twice if files.empty() but I would like to
know the 'proper' C++ way to do this.  Can it be done gracefully?
Use a function that returns a pointer to the first element of a vector
or 0 if the vector is empty.
This makes your function look like
pobject->Init(dataof(files), dataof(files) + files.size(), ...);
Which is not to bad (and not to far away from the C++0x solution
pobject->Init(files.data(), files.data() + files.size(), ...) if my
memory serves me)
Or subclass the vector and add a data() function (that does the same
thing)?
This is a very bad idea: for one thing, you will not be able to
support code that has already been written, and even if you rewrote
that code, there would still be the problem with third-party
libraries.

??

The existing code expects a pointer to the first and a pointer past the
last element. The code that has to interface to this code is being
written. This subclass is for code that is currently being written.

I don't know what makes you believe that. If there is no existing code-
base, the situation is a little different, but not much.
If
you receive from some other code a vector that is to be passed to that
function, you can always cast it to the subclass.

No, you can not.

/Peter
 
V

Vidar Hasfjord

Well... C-arrays can't be empty, so the analogy breaks down a bit.

True.  I may be stretching the analogy too far.
It can. As advised in another post, you can pass e.g. 0 if there are
no elements in the vector. So you write e.g. x.empty? 0: &x[0] instead
of &x[0], or you write a function if you find that to be more
readable. It is only four lines fully templated, so it really is no
big deal.
C++0x has these four lines ready for you, but they are not part of C+
+98 as originally there was no requirement that std::vector should be
able to replace built-in arrays.

This does seem like a pretty good solution for the general case and I
will use it from now on.  Unfortunately it doesn't work in this
specific instance but I never really cared about that anyway.  More
interested in the principle of it.

#include <vector>
using namespace std;

template <class T>
const T* first (const vector <T>& v, const T* null = 0) {
return v.empty () ? null : &v [0];
}

template <class T>
const T* last (const vector <T>& v, const T* null = 0) {
return first (v, null) + v.size ();
}

void test_vector_pass ()
{
void foo (const int* b, const int* e);

vector <int> v;
foo (first (v), last (v));

int empty;
foo (first (v, &empty), last (v, &empty));
}

Regards,
Vidar Hasfjord
 
A

alamaison

#include <vector>
using namespace std;

template <class T>
const T* first (const vector <T>& v, const T* null = 0) {
  return v.empty () ? null : &v [0];

}

template <class T>
const T* last (const vector <T>& v, const T* null = 0) {
  return first (v, null) + v.size ();

}

void test_vector_pass ()
{
  void foo (const int* b, const int* e);

  vector <int> v;
  foo (first (v), last (v));

  int empty;
  foo (first (v, &empty), last (v, &empty));

}

Thanks Vidar :) Very nice!
 
Z

Zachary Turner

As rarely seen but variously recommended (see C++ Coding Standards,
Sutter and Alexandrescu for example) I'm trying to pass a vector
of items to a function that expects an array.  The tricky part is
that the function expects the array to be passed half-open
(pointer to a [0], pointer to one-past-end) rather that &a[0] and
a size.  This means that I'm trying to do the following:
vector<item> files;
...fill vector...
pobject->Init(&files[0], &files[0] + files.size(), ...);
This works fine unless the vector happens to be empty which, given
that this function initialises a type of domain-specific
collection, is perfectly reasonable.  &files[0] triggers the STL
debugging with an out-of-bounds error.  The Init function itself
has no problem with the situation.  If it receives two identical
pointers it simple creates an empty collection.
Now, obviously, I can hack around this problem by passing Init a
pointer to anything twice if files.empty() but I would like to
know the 'proper' C++ way to do this.  Can it be done gracefully?
Use a function that returns a pointer to the first element of a vector
or 0 if the vector is empty.
This makes your function look like
pobject->Init(dataof(files), dataof(files) + files.size(), ...);
Which is not to bad (and not to far away from the C++0x solution
pobject->Init(files.data(), files.data() + files.size(), ...) if my
memory serves me)
Or subclass the vector and add a data() function (that does the same
thing)?
This is a very bad idea: for one thing, you will not be able to
support code that has already been written, and even if you rewrote
that code, there would still be the problem with third-party
libraries.

??

The existing code expects a pointer to the first and a pointer past the
last element. The code that has to interface to this code is being
written. This subclass is for code that is currently being written. If
you receive from some other code a vector that is to be passed to that
function, you can always cast it to the subclass.

Can you please construct a not too constructed situation that is
compatible with the situation as outlined above where subclassing would
be a problem?

Gerhard

It's still a bad idea. Subclassing a class that a) you cannot modify,
and b) does not have a virtual destructor is a recipe for disaster.
Just don't do it.
 
J

James Kanze

On Jan 10, 5:25 am, Gerhard Fiedler <[email protected]> wrote:

[...]
It's still a bad idea. Subclassing a class that a) you cannot
modify, and b) does not have a virtual destructor is a recipe
for disaster. Just don't do it.

It's such a bad idea that the standard more or less requires it
in some cases. I regularly derive from std::iterator<>,
std::unary_function<> and std::binary_function<>, for example.
I also have some classes of my own that are designed to be used
in a similar manner.

Generally speaking, std::vector wasn't designed to be used as a
base class, so derivation from it should be very much an
exception. But in this particular case, the exception seems
justified, and I don't see any problem with it.
 
P

peter koch

On Jan 10, 5:25 am, Gerhard Fiedler <[email protected]> wrote:

    [...]




It's still a bad idea.  Subclassing a class that a) you cannot
modify, and b) does not have a virtual destructor is a recipe
for disaster.  Just don't do it.

It's such a bad idea that the standard more or less requires it
in some cases.  I regularly derive from std::iterator<>,
std::unary_function<> and std::binary_function<>, for example.
I also have some classes of my own that are designed to be used
in a similar manner.

Generally speaking, std::vector wasn't designed to be used as a
base class, so derivation from it should be very much an
exception.  But in this particular case, the exception seems
justified, and I don't see any problem with it.

While I have no problems deriving from classes that are not designed
with derivation in mind, I believe there should be some kind of
justification for doing so. In this case, there is no justification
whatsoever.

/Peter
 
G

Gerhard Fiedler

While I have no problems deriving from classes that are not designed
with derivation in mind, I believe there should be some kind of
justification for doing so. In this case, there is no justification
whatsoever.

The justification (and "father" of the idea) would be this (on this
thread, by you, a while ago):
Which is not to bad (and not to far away from the C++0x solution
pobject->Init(files.data(), files.data() + files.size(), ...) if my
memory serves me)

Gerhard
 
P

peter koch

The justification (and "father" of the idea) would be this (on this
thread, by you, a while ago):

Im sorry if that remark caused anyone to believe that inheritance
would be the way to go.
In the current situation, inheritance has no advantage from a free
function - e.g. the one suggested by Vidar Hasfjord elsethread. (I
would only have one function - and not two as given by Vidar, but that
is a minor issue).

/Peter
 
V

Vidar Hasfjord

Im sorry if that remark caused anyone to believe that inheritance
would be the way to go.
In the current situation, inheritance has no advantage from a free
function - e.g. the one suggested by Vidar Hasfjord elsethread. (I
would only have one function - and not two as given by Vidar, but that
is a minor issue).

The two-function solution is similar to Boost.Range. Taking it a step
further:

pointer_range <int> r (v);
foo (r.begin (), r.end ());

This fully encapsulates the empty case.

Regards,
Vidar Hasfjord
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top