繁体   English   中英

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

[英]How to get the address of the std::vector buffer start most elegantly?

我想使用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() );

上面的代码有效,但是这个&(buffer[0])看起来很难看。 是否有更优雅的方式来实现相同的目标?

没人知道这真是奇怪! 在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);

规格在这里

好吧,你可以删除一组parens:

&buffer[0]

但这是常见的,惯用的方式。 如果真的冒犯了你,我想你可以使用一个模板 - 比如:

template <typename T> 
T * StartOf( std::vector <T> & v ) {
    return &v[0];
}

实际上, &buffer[0]的主要问题(注意没有parantheses)并不是说它不是很漂亮。 (无论如何这都是主观的。我记得当我第一次学会使用STL时buffer.begin(), buffer.end()发现buffer.begin(), buffer.end()根本不是很好。)

主要问题是,只要buffer为空,它就会调用未定义的行为 - 大多数代码都不会检查它。 这就是我将这些放入我的工具箱的原因:

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

使用这些,您可以将代码编写为

callFunction( begin_ptr(buffer), buffer.size() );

是否begin_ptr(buffer)&buffer[0]更漂亮,由你决定。 但是,鉴于应该为每个指针函数参数检查NULL ,它肯定更安全。

但是这个&(buffer[0])看起来很难看

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

&buffer[0]

没有。

尝试&(buffer.front()) ,但它不是更漂亮:)

优雅的方法是更改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() );

你甚至可以为所有这些函数创建包装器(使用不同的类型,而不仅仅是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 ) );
}

类型T将被正确推导出来(如std::vector<sometype> ),你仍然可以编写callFunction( buffer.begin(), buffer.end() );

请注意,您不能将模板函数声明为void callFunction( typename std::vector<typename T::value_type>::iterator begin_it, typename std::vector<typename T::value_type>::iterator end_it )就像最近提出的那样对此答案的编辑,因为在这种情况下,您将获得deducion错误。

它看起来很丑陋的原因是因为你处于漂亮而干净的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() );
}

并在客户端代码中调用它。

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

对于这些函数,我使用了一个实用程序类SizedPtr<T> ,它基本上包含一个指针和一个元素计数。 一组转换器函数从不同的输入创建SizedPtr<T> 因此呼叫变为:

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

甚至可以向SizedPtr添加一个隐式的std::vector构造SizedPtr ,但我想避免这种依赖。

仅当callFunction在您的控制之下时, callFunction 如果您在一个应用程序中使用不同的矢量类型并且想要合并,那么很高兴与您合作。 如果你通常使用std::vector ,那么它几乎没有意义。

大致:

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, ...

}

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

如前所述,没有。

原因是&buffer [0]是标准保证获取向量缓冲区的唯一方法。

如果你只是为了它的RAII属性使用std::vector (这样它就会为你释放内存),而你实际上并不需要它来调整大小或任何东西,你可能最好使用Boost scoped_array

boost::scoped_array<TCHAR> buffer( new TCHAR[neededLength] );
callFunction( buffer.get(), neededLength );

scoped_array超出范围时,它将调用数组上的delete[]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM