Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Passing a vector to a function expecting an array (http://www.velocityreviews.com/forums/t658698-passing-a-vector-to-a-function-expecting-an-array.html)

alamaison 01-09-2009 07:57 PM

Passing a vector to a function expecting an array
 
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

peter koch 01-09-2009 08:42 PM

Re: Passing a vector to a function expecting an array
 
On 9 Jan., 20:57, alamaison <aw...@doc.ic.ac.uk> wrote:
> 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


Gerhard Fiedler 01-09-2009 09:13 PM

Re: Passing a vector to a function expecting an array
 
On 2009-01-09 18:42:30, peter koch wrote:

> On 9 Jan., 20:57, alamaison <aw...@doc.ic.ac.uk> wrote:
>> 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

alamaison 01-09-2009 10:51 PM

Re: Passing a vector to a function expecting an array
 
On Jan 9, 8:42*pm, peter koch <peter.koch.lar...@gmail.com> wrote:

> > 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.


Noah Roberts 01-09-2009 11:31 PM

Re: Passing a vector to a function expecting an array
 
alamaison wrote:
> 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.

alamaison 01-10-2009 12:53 AM

Re: Passing a vector to a function expecting an array
 
> > > > vector<item> files;
> > > > ...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.


On Jan 9, 11:38 pm, Paavo Helde <pa...@nospam.please.ee> wrote:
> 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.


On Jan 9, 11:31 pm, Noah Roberts <n...@nowhere.com> wrote:
> 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

peter koch 01-10-2009 01:56 AM

Re: Passing a vector to a function expecting an array
 
[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

peter koch 01-10-2009 01:58 AM

Re: Passing a vector to a function expecting an array
 
On 9 Jan., 22:13, Gerhard Fiedler <geli...@gmail.com> wrote:
> On 2009-01-09 18:42:30, peter koch wrote:
>
>
>
>
>
> > On 9 Jan., 20:57, alamaison <aw...@doc.ic.ac.uk> wrote:
> >> 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

alamaison 01-10-2009 02:07 AM

Re: Passing a vector to a function expecting an array
 
On Jan 10, 1:56*am, peter koch <peter.koch.lar...@gmail.com> wrote:
>
> 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.

Gerhard Fiedler 01-10-2009 11:25 AM

Re: Passing a vector to a function expecting an array
 
On 2009-01-09 23:58:47, peter koch wrote:

>>>> 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


All times are GMT. The time now is 11:00 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.