views:

126

answers:

4

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.

+7  A: 

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
Matthieu M.
UncleBens
+1  A: 

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;

Joe Gauterin
A: 

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
Sadly you are mistaken. MSVC2008's vector has assertions on `operator[]`.
shoosh
Thank you for enlightening me!
acanaday
As a follow up, I've learned that the following `#define _SECURE_SCL 0` will disable this behavior.
acanaday
+1  A: 

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