6

Sometimes it is useful to use the starting address of an std::vector and temporarily treat that address as the address of a regularly allocated buffer.
For instance replace this:

 char* buf = new char[size];
 fillTheBuffer(buf, size);
 useTheBuffer(buf, size);
 delete[] buf;

With This:

 vector<char> buf(size);
 fillTheBuffer(&buf[0], size);
 useTheBuffer(&buf[0], size);

The advantage of this is of course that the buffer is deallocated automatically and I don't have to worry about the delete[].

The problem I'm having with this is when size == 0. In that case the first version works ok. An empty buffer is "allocated" and the subsequent functions do nothing size they get size == 0.
The second version however fails if size == 0 since calling buf[0] may rightly contain an assertion that 0 < size.

So is there an alternative to the idiom &buf[0] that returns the address of the start of the vector even if the vector is empty?

I've also considered using buf.begin() but according to the standard it isn't even guaranteed to return a pointer.

shoosh
  • 76,898
  • 55
  • 205
  • 325
  • This looks like an oversight in the STL library. C++ allows you to allocate `new T[0]` and return a valid pointer for situations like this, but most implementations of the STL assert just in case you're assigning to that element or something. – AshleysBrain Apr 28 '10 at 09:59
  • How would it know the difference between `&buf[0]` and `buf[0] = 1` ? – shoosh Apr 28 '10 at 10:47

4 Answers4

8

I guess you'd just have to check.

Perhaps a utility function:

template <class T, class Alloc>
T* data(std::vector<T, Alloc>& vec)
{
    return vec.empty() ? 0 : &vec[0];
}

template <class T, class Alloc>
const T* data(const std::vector<T, Alloc>& vec)
{
    return vec.empty() ? 0 : &vec[0];
}
UncleBens
  • 40,819
  • 6
  • 57
  • 90
  • 1
    1st remark: is it worth investing on `boost::addressof` in case `T` has an overloaded `&` operator ? 2nd remark: a second template parameter `Alloc` would make the function a bit more universal. – Matthieu M. Apr 28 '10 at 11:16
  • 1
    @Matthieu: Regarding the first remark: http://stackoverflow.com/questions/2719832/why-is-overloading-operator-prohibited-for-classes-stored-in-stl-containers. You can't store a type for which `&t` doesn't return its address. - Second remark added to the answer. – UncleBens Apr 28 '10 at 12:00
1

There's no function for that, even though std::basic_string has data() which does exactly what you need.

You'll have to use something like buf.size()?&buf[0]:0;

JoeG
  • 12,994
  • 1
  • 38
  • 63
1

I think you should be safe in either case. I believe that the differences between vector::operator[int] and vector::at(int) is that the [] operator overload specifically does not perform bounds checking. Using buf[0] should be free of assertions!

acanaday
  • 400
  • 1
  • 11
1

If you can change fillTheBuffer and useTheBuffer to take a pair of iterators, then you'll be solving the problem the same way the standard library solved it.

Ben
  • 1,298
  • 11
  • 12