I want to use std::vector for dynamically allocating memory. The scenario is:
int neededLength = computeLength(); // some logic here
// this will allocate t
Actually, the main problem with &buffer[0]
(note the absence of parantheses) isn't that it isn't really pretty. (That's subjective anyway. I remember finding buffer.begin(), buffer.end()
not pretty at all, when I first learned to use the STL.)
The main problem is that it invokes undefined behavior whenever buffer
is empty -- and most code never checks for that. That's why I put these into my toolbox:
template <class T, class TAl>
inline T* begin_ptr(std::vector<T,TAl>& v)
{return v.empty() ? NULL : &v[0];}
template <class T, class TAl>
inline const T* begin_ptr(const std::vector<T,TAl>& v)
{return v.empty() ? NULL : &v[0];}
template <class T, class TAl>
inline T* end_ptr(std::vector<T,TAl>& v)
{return v.empty() ? NULL : (begin_ptr(v) + v.size());}
template <class T, class TAl>
inline const T* end_ptr(const std::vector<T,TAl>& v)
{return v.empty() ? NULL : (begin_ptr(v) + v.size());}
Using these, you can write your code as
callFunction( begin_ptr(buffer), buffer.size() );
Whether begin_ptr(buffer)
is prettier than &buffer[0]
is left for you to decide. However, given that NULL
should be checked for every pointer function argument, it definitely is more safe.
but this
&(buffer[0])
looks ugly
It’s the normal way. You can omit the parentheses, though:
&buffer[0]
As already said, no.
The reason is that &buffer[0] is the only way guarantied by the standard to get the adresse of the vector buffer.
Well, you can remove one set of parens:
&buffer[0]
but that is the common, idiomatic way of doing it. If it really offends you, I suppose you could use a template - something like:
template <typename T>
T * StartOf( std::vector <T> & v ) {
return &v[0];
}
For functions like these, I use a utility class, SizedPtr<T>
that basically holds a pointer and an element count. A set of converter functions creates the SizedPtr<T>
from different inputs. So the call changes to:
vector<TCHAR> foo;
callFunction(sizedptr(foo));
One could even add an implicit std::vector
constructor to SizedPtr
, but I wanted to avoid this dependency.
This helps only if callFunction
is under your control. It is a pleasure to work with, if you work with different vector types in one application and you want to consolidate. If you generally work with std::vector
, it's mostly pointless.
Roughly:
template<typename T>
class SizedPtr
{
T * m_ptr;
size_t m_size;
public:
SizedPtr(T* p, size_t size) : ... {}
T * ptr() { return m_ptr; }
size_t size() const { return m_size; }
// index access, STL container interface, Sub-Sequence, ...
}
The idea behind this is to separate the operation - manipulating a contiguous sequence of elements - from the storage (std::vector). It's similar to what STL does with iterators, but avoids template infection.
Elegant way would be to change callFunction
or to write wrapper for it as follows:
// legacy function
void callFunction( TCHAR* buf, int buf_size)
{
// some code
}
// helpful template
void callFunction( std::vector<TCHAR>::iterator begin_it, std::vector<TCHAR>::iterator end_it )
{
callFunction( &*begin_it, std::distance( begin_it, end_it ) );
}
// somewhere in the code
int neededLength = computeLength();
std::vector<TCHAR> buffer( neededLength );
callFunction( buffer.begin(), buffer.end() );
You could even make wrapper for all such functions (with different types, not only TCHAR):
template<typename T>
void callFunction( T begin_it, typename std::vector<typename T::value_type>::iterator end_it )
{
callFunction( &*begin_it, std::distance( begin_it, end_it ) );
}
Type T will be properly deduced (as std::vector<sometype>
) and you'll be able still write callFunction( buffer.begin(), buffer.end() );
.
Note that you cannot declare template function as void callFunction( typename std::vector<typename T::value_type>::iterator begin_it, typename std::vector<typename T::value_type>::iterator end_it )
as someone proposed recently as an edit to this answer, because in that case you will get the deducion error.