C++ 如何最优雅地获取std::vector缓冲区的地址?

C++ 如何最优雅地获取std::vector缓冲区的地址?,c++,stl,vector,C++,Stl,Vector,我想使用std::vector动态分配内存。情况是: int neededLength = computeLength(); // some logic here // this will allocate the buffer std::vector<TCHAR> buffer( neededLength ); // call a function that accepts TCHAR* and the number of elements callFunction(

我想使用std::vector动态分配内存。情况是:

int neededLength = computeLength(); // some logic here

// this will allocate the buffer     
std::vector<TCHAR> buffer( neededLength );

// call a function that accepts TCHAR* and the number of elements
callFunction( &(buffer[0]), buffer.size() );
int neededLength=computeLength();//这里有些逻辑
//这将分配缓冲区
std::向量缓冲区(需要的长度);
//调用接受TCHAR*和元素数的函数
callFunction(&(buffer[0]),buffer.size();
上面的代码可以工作,但是这个
&(缓冲区[0])
看起来很难看。有没有更优雅的方法来达到同样的效果呢?

试试
&(buffer.front())
,但它并不漂亮:)

但是这个
&(缓冲区[0])
看起来很难看

这是正常的方式。但是,您可以省略括号:

&buffer[0]

否。

您可以删除一组参数:

&buffer[0]
但这是常见的惯用方法。如果它真的冒犯了你,我想你可以使用一个模板,比如:

template <typename T> 
T * StartOf( std::vector <T> & v ) {
    return &v[0];
}
模板
T*StartOf(标准::矢量和v){
返回&v[0];
}

优雅的方法是更改
callFunction
或按如下方式为其编写包装器:

// 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() );
//遗留函数
void callFunction(TCHAR*buf,int buf_size)
{
//一些代码
}
//有用模板
void callFunction(std::vector::iterator begin_it,std::vector::iterator end_it)
{
callFunction(&*begin_-it,std::distance(begin_-it,end_-it));
}
//代码中的某个地方
int neededLength=计算长度();
std::向量缓冲区(需要的长度);
callFunction(buffer.begin(),buffer.end());
您甚至可以为所有这类函数制作包装器(使用不同的类型,而不仅仅是TCHAR):

模板
void callFunction(T begin_it,typename std::vector::iterator end_it)
{
callFunction(&*begin_-it,std::distance(begin_-it,end_-it));
}
类型T将被正确推导(如
std::vector
),您仍然可以编写
callFunction(buffer.begin(),buffer.end())

请注意,您不能将模板函数声明为
void callFunction(typename std::vector::iterator begin\u it,typename std::vector::iterator end\u it)
,因为在这种情况下,您将得到推断错误。

如前所述,否


原因是,缓冲器[0 ]是标准的唯一方法,以获得向量缓冲区的地址。

< P>它看起来很丑陋的原因是因为你处于漂亮干净的C++风格代码和干净整洁的C风格代码的边界。C++代码使用迭代器,C代码使用指针和大小。 您可以创建一些胶水来避免这些问题:

template< typename at_Container, typename at_Function >
void for_container( at_Container& c, at_Function f ) {
    f( &c[0], c.size() );
}
template
_容器的空隙(在_容器和c处,在_函数f处){
f(&c[0],c.size());
}
并在客户端代码中调用它

void afunction( int* p, size_t n ) { 
   for( int* p = ap; p != ap+n; ++p ) {
     printf( "%d ", *p );
   }
}

void clientcode() {
   std::vector<int> ints(30,3);
   for_container( ints, afunction );
}
void函数(int*p,size\t n){
对于(int*p=ap;p!=ap+n;+p){
printf(“%d”,*p);
}
}
void clientcode(){
std::向量整数(30,3);
用于集装箱(ints、A功能);
}

对于这样的函数,我使用了一个实用类,
SizedPtr
,它基本上包含一个指针和一个元素计数。一组转换器功能从不同输入创建
SizedPtr
。因此,呼叫更改为:

vector<TCHAR> foo;
callFunction(sizedptr(foo));

这背后的思想是将操作(操作连续的元素序列)与存储(std::vector)分离。它类似于STL对迭代器所做的操作,但避免了模板感染。

实际上,
&buffer[0]
(注意没有偏执)的主要问题并不是它真的不漂亮。(无论如何,这是主观的。我记得当我第一次学习使用STL时,我发现
buffer.begin(),buffer.end()
一点也不漂亮。)

主要的问题是,每当
缓冲区
为空时,它就会调用未定义的行为,而大多数代码从不检查这一点。这就是我为什么把这些放进工具箱的原因:

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());}

begin\u ptr(buffer)
是否比
和buffer[0]
更漂亮,由您决定。然而,考虑到应该为每个指针函数参数检查
NULL
,它肯定更安全

如果您仅为其RAII属性使用
std::vector
(这样它就可以为您释放内存),并且实际上不需要它来调整大小或做任何事情,那么最好使用

boost::作用域_数组缓冲区(新的TCHAR[neededLength]);
callFunction(buffer.get(),neededLength);

scoped_array
将在数组超出范围时调用
delete[]

真奇怪,没有人知道这一点!!! 在C++11中,您可以使用:

buffer.data()
它可以得到向量的地址 我已经测试过了:

vector<char>buffer;
buffer.push_back('w');
buffer.push_back('h');
buffer.push_back('a');
buffer.push_back('t');
buffer.push_back('\0');
char buf2[10];
memcpy(buf2,buffer.data(),10);
vectorbuffer;
缓冲器。推回(“w”);
缓冲器。推回(“h”);
缓冲器。推回(“a”);
缓冲器。推回(“t”);
buffer.push_back('\0');
char-buf2[10];
memcpy(buf2,buffer.data(),10);

规范。

您应该将缓冲区重命名为elegantBuffer…:)你不能让callFunction接受向量吗?在我看来,这才是真正优雅的方式。否则,你会被困在C和C++之间不优雅的无人区。@ BiMuth:我知道这是一个很好的解决方案,改变消费者的功能来接受向量,但这不是一个选项。事实上,我只使用向量作为预先未知大小的allocate once数组。如果您只使用它来分配once,则可能会牺牲范围自动删除的便利性,并使用TCHAR*buffer=new TCHAR[neededLength];记住在完成时删除[]缓冲区。@cheshirekow:记住是这里的关键问题。如果抛出异常,
delete[]
将不会运行,因此我必须为
delete
调用缓冲区使用单独的try-catch。这就是为什么
vector
或类似的东西更可取的原因。如果简洁表达了错误的答案,那它就毫无用处了。Neil和我都发布了更简单的解决方案(大大减少了17%的字符数)
callFunction( begin_ptr(buffer), buffer.size() );
boost::scoped_array<TCHAR> buffer( new TCHAR[neededLength] );
callFunction( buffer.get(), neededLength );
buffer.data()
vector<char>buffer;
buffer.push_back('w');
buffer.push_back('h');
buffer.push_back('a');
buffer.push_back('t');
buffer.push_back('\0');
char buf2[10];
memcpy(buf2,buffer.data(),10);