Topic: is &(vector[0]) always valid?


Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Mon, 22 Jan 2007 05:42:13 GMT
Raw View
On Sat, 20 Jan 2007 07:21:08 GMT, John Salmon wrote:

>I was under the impression that the following was always valid:
>
>std::vector<T> v;
>.
>T *p = &(v[0]);
>
>But I was recently told that care was needed in case the vector was
>empty, i.e., when v.size() == 0.

That's right. Of course you can (and probably should) use v.empty() in
lieu of v.size() == 0.

>I'm hoping that the above expression is fine, even if v is empty, but
>that if you try to dereference p, you're in trouble.
>
>If the above isn't ok, I'd have to write:
>
>T *p = (v.size()!=0)? &(v[0]) : 0;
>
>I took a look in the C++98 standard, and couldn't find anything to
>confirm my hope.  I see from Table 68 that the expression has the
>"operational sematics" of
>
>&(*(v.begin() + 0))
>
>which sure *seems* like it might in turn be "operationally equivalent"
>to v.begin(), which sure seems safe, even for an empty vector.

It isn't equivalent: there's an "actual" dereferencing going on, which
doesn't elide itself with the & operator. Consider --among other
things-- that you are not necessarily dealing with the built-in * and
& operators (but there's no elision guarantee in current C++, or C90,
even for the built-in case).

You might want to have a look at the pg. 42 issue at

  <http://www.research.att.com/~bs/3rd_issues.html>,

which is very similar.

  Genny.

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: clarkcox3@gmail.com ("Clark S. Cox III")
Date: Mon, 22 Jan 2007 05:42:44 GMT
Raw View
John Salmon wrote:
> I was under the impression that the following was always valid:
>
> std::vector<T> v;
> ..
> T *p = &(v[0]);
>
> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.

You were told correctly. Calling v[x], where x is >= v.size() is
undefined behavior; period.

> I'm hoping that the above expression is fine, even if v is empty, but
> that if you try to dereference p, you're in trouble.
>
> If the above isn't ok, I'd have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;
>
> I took a look in the C++98 standard, and couldn't find anything to
> confirm my hope.  I see from Table 68 that the expression has the
> "operational sematics" of
>
> &(*(v.begin() + 0))
>
> which sure *seems* like it might in turn be "operationally equivalent"
> to v.begin(), which sure seems safe, even for an empty vector.  But I
> now feel myself to be on very thin ice.
>
> So, can I write:
>
> T *p = &(v[0]);
>
>  or do I have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;

You have to write the later (or some variation thereof).

--
Clark S. Cox III
clarkcox3@gmail.com

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <james.kanze@gmail.com>
Date: Mon, 22 Jan 2007 09:36:26 CST
Raw View
"Alf P. Steinbach" wrote:
> * John Salmon:

> > So, can I write:

> > T *p = &(v[0]);

> >  or do I have to write:

> > T *p = (v.size()!=0)? &(v[0]) : 0;

> The latter.

>    23.1/7 "If the container is empty, then 'begin() == end()'".
>    24.1/5 Explaining that one-past-the-end iterators are past-the-end
> values, then "The library never assumes that past-the-end values are
> dereferencable".

> Hence v[0] by equivalence to &(*(begin()+0)) performs an invalid
> dereferencing when the vector is empty.  In more practical terms, the
> vector need not have a buffer if it's empty.  But I suspect that with
> most compiler and standard library implementations (all?) you can get
> away with it if the vector's /capacity/ is greater than zero.

Changing the capacity doesn't make it work with g++ nor with
VC++.  There are thus at least two major implementations (the
two most widely used?) where it actually does fail at runtime.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "peter koch" <peter.koch.larsen@gmail.com>
Date: Tue, 23 Jan 2007 12:07:53 CST
Raw View
James Kanze wrote:
> "Alf P. Steinbach" wrote:
> > * John Salmon:
>
> > > So, can I write:
>
> > > T *p = &(v[0]);
>
> > >  or do I have to write:
>
> > > T *p = (v.size()!=0)? &(v[0]) : 0;
>
> > The latter.
>
> >    23.1/7 "If the container is empty, then 'begin() == end()'".
> >    24.1/5 Explaining that one-past-the-end iterators are past-the-end
> > values, then "The library never assumes that past-the-end values are
> > dereferencable".
>
> > Hence v[0] by equivalence to &(*(begin()+0)) performs an invalid
> > dereferencing when the vector is empty.  In more practical terms, the
> > vector need not have a buffer if it's empty.  But I suspect that with
> > most compiler and standard library implementations (all?) you can get
> > away with it if the vector's /capacity/ is greater than zero.
>
> Changing the capacity doesn't make it work with g++ nor with
> VC++.  There are thus at least two major implementations (the
> two most widely used?) where it actually does fail at runtime.

Which is logical. I do not know of a hardware platform where
&(*begin()) would physically access memory, so I'd expect &(*begin())
to return a pointer in all cases when the implementation does not
perform some kind of  explicit check. And that check would be related
to size, not capacity.

/Peter


---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jsalmon@thesalmons.org (John Salmon)
Date: Sat, 20 Jan 2007 07:21:08 GMT
Raw View
I was under the impression that the following was always valid:

std::vector<T> v;
.
T *p = &(v[0]);

But I was recently told that care was needed in case the vector was
empty, i.e., when v.size() == 0.

I'm hoping that the above expression is fine, even if v is empty, but
that if you try to dereference p, you're in trouble.

If the above isn't ok, I'd have to write:

T *p = (v.size()!=0)? &(v[0]) : 0;

I took a look in the C++98 standard, and couldn't find anything to
confirm my hope.  I see from Table 68 that the expression has the
"operational sematics" of

&(*(v.begin() + 0))

which sure *seems* like it might in turn be "operationally equivalent"
to v.begin(), which sure seems safe, even for an empty vector.  But I
now feel myself to be on very thin ice.

So, can I write:

T *p = &(v[0]);

 or do I have to write:

T *p = (v.size()!=0)? &(v[0]) : 0;

Thanks,
John Salmon

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Alan Johnson <awjcs@yahoo.com>
Date: Sat, 20 Jan 2007 09:25:31 CST
Raw View
John Salmon wrote:
> I was under the impression that the following was always valid:
>
> std::vector<T> v;
> .
> T *p = &(v[0]);
>
> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.
>
> I'm hoping that the above expression is fine, even if v is empty, but
> that if you try to dereference p, you're in trouble.
>
> If the above isn't ok, I'd have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;
>
> I took a look in the C++98 standard, and couldn't find anything to
> confirm my hope.  I see from Table 68 that the expression has the
> "operational sematics" of
>
> &(*(v.begin() + 0))
>
> which sure *seems* like it might in turn be "operationally equivalent"
> to v.begin(), which sure seems safe, even for an empty vector.  But I
> now feel myself to be on very thin ice.
>
> So, can I write:
>
> T *p = &(v[0]);
>
>  or do I have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;
>
> Thanks,
> John Salmon
>

v[0] is NOT valid for an empty vector, and therefore &v[0] is not valid
either.  You are right about the operational semantics, but neither is
that expression valid.  If the vector is empty, then begin() == end(),
and you are therefore "dereferencing" the end() iterator.

As for the alternate expression you propose, using empty() rather than
size() would be more idiomatic, and might be more efficient, depending
on the implementation:

T *p = v.empty() ? 0 : &(v[0]) ;

--
Alan Johnson

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Carl Barron <cbarron413@adelphia.net>
Date: Sat, 20 Jan 2007 09:26:44 CST
Raw View
In article <m3y7nyqxoy.fsf@river.fishnet>, John Salmon
<jsalmon@thesalmons.org> wrote:

> I was under the impression that the following was always valid:
>
> std::vector<T> v;
> .
> T *p = &(v[0]);
>
> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.
   its not valid if v.size()==0.
   template <class T,class A>
   inline T *data(std::vector<T,A> &v)
   {
      return v.empty() ? 0: &v[0];
   }
   is an easy work around.   Recent drafts of the standard provide
vector with a data() member function which does this, but your
implementation probably does not.

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: rpbg123@yahoo.com (Roland Pibinger)
Date: Sat, 20 Jan 2007 09:27:13 CST
Raw View
On Sat, 20 Jan 2007 07:21:08 GMT, John Salmon wrote:
>So, can I write:
>
>T *p = &(v[0]);
>
> or do I have to write:
>
>T *p = (v.size()!=0)? &(v[0]) : 0;

What would be the address of the first element of an empty vector?

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jkherciueh@gmx.net (Kai-Uwe Bux)
Date: Sat, 20 Jan 2007 15:26:48 GMT
Raw View
John Salmon wrote:

>
> I was under the impression that the following was always valid:
>
> std::vector<T> v;
> .
> T *p = &(v[0]);
>
> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.
>
> I'm hoping that the above expression is fine, even if v is empty, but
> that if you try to dereference p, you're in trouble.

If v is empty, once you evaluate v[0] you have undefined behavior. More
importantly, an implementation of std::vector<> is perfectly free and maybe
even well-advised to do something like:

  T& operator[] ( size_type i ) {
    assert( i < this->size() );
    return( this->data[i] );
  }

Because of the assert(), your program could crash depending on compilation
options.

> If the above isn't ok, I'd have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;
>
> I took a look in the C++98 standard, and couldn't find anything to
> confirm my hope.  I see from Table 68 that the expression has the
> "operational sematics" of
>
> &(*(v.begin() + 0))
>
> which sure *seems* like it might in turn be "operationally equivalent"
> to v.begin(), which sure seems safe, even for an empty vector.  But I
> now feel myself to be on very thin ice.
>
> So, can I write:
>
> T *p = &(v[0]);
>
>  or do I have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;

Why do you insist on using T* anyway? What is the reason not to use
std::vector<T>::iterator?


Best

Kai-Uwe Bux

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: ark@acm.org ("Andrew Koenig")
Date: Sat, 20 Jan 2007 17:01:19 GMT
Raw View
"John Salmon" <jsalmon@thesalmons.org> wrote in message
news:m3y7nyqxoy.fsf@river.fishnet...

> I was under the impression that the following was always valid:

> std::vector<T> v;

> T *p = &(v[0]);

> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.

Whoever told you that is correct.

> I'm hoping that the above expression is fine, even if v is empty, but
> that if you try to dereference p, you're in trouble.

Sorry to dash your hopes, but...

> If the above isn't ok, I'd have to write:

> T *p = (v.size()!=0)? &(v[0]) : 0;

Right.

>
> I took a look in the C++98 standard, and couldn't find anything to
> confirm my hope.  I see from Table 68 that the expression has the
> "operational sematics" of
>
> &(*(v.begin() + 0))
>
> which sure *seems* like it might in turn be "operationally equivalent"
> to v.begin(), which sure seems safe, even for an empty vector.  But I
> now feel myself to be on very thin ice.

You are.  v.begin() + 0 is always equivalent to v.begin(), but &(*v.begin())
is undefined if v is empty.

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: Sat, 20 Jan 2007 14:39:54 CST
Raw View
In article <m3y7nyqxoy.fsf@river.fishnet>, John Salmon
<jsalmon@thesalmons.org> writes
>I was under the impression that the following was always valid:
>
>std::vector<T> v;
>.
>T *p = &(v[0]);
>
>But I was recently told that care was needed in case the vector was
>empty, i.e., when v.size() == 0.

You were correctly informed. The problem is that v[0] has undefined
behaviour if there are no elements. That means that &(v[0]) has
undefined behaviour. This is not that unreasonable because an empty
vector does not have a location for any element so there will be no
address.

Changing this would have required a special rule for &(v[0]). Instead
you must write something like:

T *p = v.size() ? &(v[0]) : 0;

If there is any possibility that v is an empty vector. (There are
several variations on the above definition but I tend to use a limited
subset of the member functions of vector rather than remember the exact
spelling of all of them.)


--
Francis Glassborow      ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Sat, 20 Jan 2007 20:41:01 GMT
Raw View
On Sat, 20 Jan 2007 09:26:44 CST, Carl Barron wrote:

>In article <m3y7nyqxoy.fsf@river.fishnet>, John Salmon
><jsalmon@thesalmons.org> wrote:
>
>> I was under the impression that the following was always valid:
>>
>> std::vector<T> v;
>> .
>> T *p = &(v[0]);
>>
>> But I was recently told that care was needed in case the vector was
>> empty, i.e., when v.size() == 0.
>   its not valid if v.size()==0.
>   template <class T,class A>
>   inline T *data(std::vector<T,A> &v)
>   {
>      return v.empty() ? 0: &v[0];
>   }
>   is an easy work around.

Yes, better providing two overloads, though (const/non-const). Less
importantly, &v.front() could be used, and perhaps preferred to &v[0].

>Recent drafts of the standard provide
>vector with a data() member function which does this, but your
>implementation probably does not.

Yep, lib issue 464; I guess you are one of the few people who noticed
it :-)

Genny.

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: grahn+nntp@snipabacken.dyndns.org (Jorgen Grahn)
Date: Sat, 20 Jan 2007 20:40:48 GMT
Raw View
["Followup-To:" header set to comp.lang.c++.]

On Sat, 20 Jan 2007 07:21:08 GMT, John Salmon <jsalmon@thesalmons.org> wrote:
>
> I was under the impression that the following was always valid:
>
> std::vector<T> v;
> .
> T *p = &(v[0]);
>
> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.

Or when v.empty().

.
>  or do I have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;

That, or:

T *p = v.empty()? 0: &(v[0]);

std::vector<T>::size() is constant time, I think, but that's not the case
for other containers. So when you really want to test for (non-)emptiness,
it's good to make a habit of using empty().

/Jorgen

--
  // Jorgen Grahn <grahn@        Ph'nglui mglw'nafh Cthulhu
\X/     snipabacken.dyndns.org>  R'lyeh wgah'nagl fhtagn!

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: howard.hinnant@gmail.com (Howard Hinnant)
Date: Sat, 20 Jan 2007 20:40:32 GMT
Raw View
In article <m3y7nyqxoy.fsf@river.fishnet>,
 jsalmon@thesalmons.org (John Salmon) wrote:

> I was under the impression that the following was always valid:
>
> std::vector<T> v;
> .
> T *p = &(v[0]);
>
> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.
>
> I'm hoping that the above expression is fine, even if v is empty, but
> that if you try to dereference p, you're in trouble.
>
> If the above isn't ok, I'd have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;
>
> I took a look in the C++98 standard, and couldn't find anything to
> confirm my hope.  I see from Table 68 that the expression has the
> "operational sematics" of
>
> &(*(v.begin() + 0))
>
> which sure *seems* like it might in turn be "operationally equivalent"
> to v.begin(), which sure seems safe, even for an empty vector.  But I
> now feel myself to be on very thin ice.
>
> So, can I write:
>
> T *p = &(v[0]);
>
>  or do I have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;

You have to write the latter (unfortunately).  It is the dereference
caused by v[0] which is the trouble maker.

Fwiw the working draft for C++0X has added a new member function to
vector so that you no longer have to do this:

T *p = v.data();

Reference LWG 464:
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#464

Your vendor may or may not yet support this new member as C++0X isn't
official yet.

-Howard

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <james.kanze@gmail.com>
Date: Sat, 20 Jan 2007 14:40:30 CST
Raw View
John Salmon wrote:
> I was under the impression that the following was always valid:

> std::vector<T> v;
> .
> T *p = &(v[0]);

> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.

> I'm hoping that the above expression is fine, even if v is empty,

It's not.  It's undefined behavior, and will core dump on some
implementations.  (It core dumps with g++ 4.0.1, for example, or
with VC++ 8.)

> but that if you try to dereference p, you're in trouble.

> If the above isn't ok, I'd have to write:

> T *p = (v.size()!=0)? &(v[0]) : 0;

> I took a look in the C++98 standard, and couldn't find anything to
> confirm my hope.  I see from Table 68 that the expression has the
> "operational sematics" of

> &(*(v.begin() + 0))

No.  The expression a[n] is the equivalent of *(v.begin() + 0)
(which is presumably the equivalent of *v.begin()).  If
v.begin() == v.end(), however, *v.begin() is undefined behavior.

> which sure *seems* like it might in turn be "operationally equivalent"
> to v.begin(), which sure seems safe, even for an empty vector.  But I
> now feel myself to be on very thin ice.

I'd say that the ice has already broken.  Your code causes a
run-time error (core dump, or its moral equivalent under
Windows) with two of the three compilers I regularly use.

> So, can I write:

> T *p = &(v[0]);

>  or do I have to write:

> T *p = (v.size()!=0)? &(v[0]) : 0;

The latter.

Given the particular guarantee for std::vector, I wonder if an
additional member function, data() might not be in order.  A
function which could be required to return a null pointer if the
vector is empty.

--
James Kanze (Gabi Software)            email: james.kanze@gmail.com
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "whyglinux" <whyglinux@gmail.com>
Date: Sat, 20 Jan 2007 14:41:20 CST
Raw View
John Salmon wrote:
> I was under the impression that the following was always valid:
>
> std::vector<T> v;
> .
> T *p = &(v[0]);
>
> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.
>
> I'm hoping that the above expression is fine, even if v is empty, but
> that if you try to dereference p, you're in trouble.
>
> If the above isn't ok, I'd have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;
>
> I took a look in the C++98 standard, and couldn't find anything to
> confirm my hope.  I see from Table 68 that the expression has the
> "operational sematics" of
>
> &(*(v.begin() + 0))
>
> which sure *seems* like it might in turn be "operationally equivalent"
> to v.begin(), which sure seems safe, even for an empty vector.  But I
> now feel myself to be on very thin ice.
>
> So, can I write:
>
> T *p = &(v[0]);
>
>  or do I have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;
>
> Thanks,
> John Salmon
>
> ---
> [ 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    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]

Yes, it's undefined.

v[0] is equivalent to *v.begin(). Whether v is an empty vector or not,
v.begin() returns a valid iterator. But if v is empty, v.begin(), like
v.end(), is not a valid dereferenceable iterator, so *v.begin() is
undefined.

Note though, &(*(v.begin() + 0)) is not, as you said, "operationally
equivalent" to v.begin() because v.begin() returns an object of the
vector<T>'s iterator type while &(*(v.begin() + 0)) should return a
type of pointer to T (since operator * is overloaded here), and the
iterator type needs not to be the same as a pointer to T.

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: nospam@nospam.com ("Lynn")
Date: Sat, 20 Jan 2007 21:20:18 GMT
Raw View
> std::vector<T> v;
> .
> T *p = &(v[0]);

This works in Visual C++ 2003.   It crashes when the size is
zero in Visual C++ 2005.  I fixing this all over our code right
now.

> But I was recently told that care was needed in case the vector was
> empty, i.e., when v.size() == 0.

Yes, true.

> If the above isn't ok, I'd have to write:
>
> T *p = (v.size()!=0)? &(v[0]) : 0;

Yes, this should work OK.

Lynn


---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "david.hinkes@gmail.com" <david.hinkes@gmail.com>
Date: Sun, 21 Jan 2007 23:11:05 CST
Raw View
John Salmon wrote:
> I was under the impression that the following was always valid:
>
> std::vector<T> v;
> .
> T *p = &(v[0]);
>


I've often had this question myself. Even if this worked, isn't it
_very_ dangerous?  Consider the following:

std::vector<T> v(1);

T dummy;

v.push_back(dummy);

T * p = &(v[0]);


v.push_back(dummy);

v.push_back(dummy);

// does p still point to anything valid at this point?  Since the
push_back operations, perhaps
// internally the vector resized itself.  I wouldn't expect that the
vector object keep the same internal
// memory.

T first_element = p[0];  //is p still valid?

// Thoughts?

Dave

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: James Dennett <jdennett@acm.org>
Date: Sun, 21 Jan 2007 23:39:54 CST
Raw View
david.hinkes@gmail.com wrote:
> John Salmon wrote:
>> I was under the impression that the following was always valid:
>>
>> std::vector<T> v;
>> .
>> T *p = &(v[0]);
>>
>
>
> I've often had this question myself. Even if this worked, isn't it
> _very_ dangerous?  Consider the following:
>
> std::vector<T> v(1);
>
> T dummy;
>
> v.push_back(dummy);
>
> T * p = &(v[0]);
>
>
> v.push_back(dummy);
>
> v.push_back(dummy);
>
> // does p still point to anything valid at this point?  Since the
> push_back operations, perhaps
> // internally the vector resized itself.  I wouldn't expect that the
> vector object keep the same internal
> // memory.
>
> T first_element = p[0];  //is p still valid?
>
> // Thoughts?

This is spelled out quite clearly; after a push_back that
can cause a vector to grow beyond its capacity, iterators
and pointers to its old elements are invalidated.  In your
example, p is invalidated by the first call to v.push_back
after p was initialized.

It's dangerous is people don't know the rules on when
iterators and pointers are invalidated, but those rules
are vital to safe use of containers in any case.

Further discussion on this line is probably best removed
from comp.std.c++; followups set.

-- James

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: alfps@start.no ("Alf P. Steinbach")
Date: Mon, 22 Jan 2007 05:41:42 GMT
Raw View
* John Salmon:
>=20
> So, can I write:
>=20
> T *p =3D &(v[0]);
>=20
>  or do I have to write:
>=20
> T *p =3D (v.size()!=3D0)? &(v[0]) : 0;

The latter.

=A723.1/7 "If the container is empty, then 'begin() =3D=3D end()'".
=A724.1/5 Explaining that one-past-the-end iterators are past-the-end=20
values, then "The library never assumes that past-the-end values are=20
dereferencable".

Hence v[0] by equivalence to &(*(begin()+0)) performs an invalid=20
dereferencing when the vector is empty.  In more practical terms, the=20
vector need not have a buffer if it's empty.  But I suspect that with=20
most compiler and standard library implementations (all?) you can get=20
away with it if the vector's /capacity/ is greater than zero.

--=20
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]