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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1339470/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:37:20  来源:igfitidea点击:

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

c++stlvector

提问by sharptooth

I want to use std::vector for dynamically allocating memory. The scenario is:

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

The code above works, but this &(buffer[0])looks ugly. Is there a more elegant way to achieve the same?

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

回答by hyphen

It's really odd that nobody know this!!! in C++11 you could use:

真的很奇怪没人知道这个!!!在 C++11 中,你可以使用:

buffer.data()

it could get the address of the vector I have test it:

它可以获得我测试过的向量的地址:

vector<char>buffer;
buffer.push_back('w');
buffer.push_back('h');
buffer.push_back('a');
buffer.push_back('t');
buffer.push_back('
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());}
'); char buf2[10]; memcpy(buf2,buffer.data(),10);

Specification here.

规格在这里

回答by sbi

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

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

The main problem is that it invokes undefined behavior whenever bufferis empty -- and most code never checks for that. That's why I put these into my toolbox:

主要问题是它在buffer为空时调用未定义的行为——而且大多数代码从不检查它。这就是我将这些放入我的工具箱的原因:

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

Using these, you can write your code as

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

&buffer[0]

Whether begin_ptr(buffer)is prettier than &buffer[0]is left for you to decide. However, given that NULLshould be checked for every pointer function argument, it definitely is more safe.

是否begin_ptr(buffer)&buffer[0]留给你决定的更漂亮。然而,考虑到NULL每个指针函数参数都应该检查,它肯定更安全。

回答by sbi

Well, you can remove one set of parens:

好吧,您可以删除一组括号:

template <typename T> 
T * StartOf( std::vector <T> & v ) {
    return &v[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:

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

&buffer[0]

回答by Konrad Rudolph

but this &(buffer[0])looks ugly

但这&(buffer[0])看起来很丑

It's the normal way. You can omit the parentheses, though:

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

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

回答by P Shved

No.

不。

回答by Michael Krelin - hacker

Try &(buffer.front()), but it's not much prettier :)

尝试&(buffer.front()),但它并没有更漂亮:)

回答by Kirill V. Lyadvinsky

Elegant way would be to change callFunctionor to write wrapper for it as follows:

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

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

You could even make wrapper for all such functions (with different types, not only TCHAR):

您甚至可以为所有此类函数(具有不同类型,不仅是 TCHAR)制作包装器:

template< typename at_Container, typename at_Function >
void for_container( at_Container& c, at_Function f ) {
    f( &c[0], c.size() );
}

Type T will be properly deduced (as std::vector<sometype>) and you'll be able still write callFunction( buffer.begin(), buffer.end() );.

类型 T 将被正确推导(作为std::vector<sometype>),您仍然可以编写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.

请注意,您不能将模板函数声明void callFunction( typename std::vector<typename T::value_type>::iterator begin_it, typename std::vector<typename T::value_type>::iterator end_it )为某人最近提出的对该答案的编辑,因为在这种情况下,您将得到推论错误。

回答by xtofl

The reason it looks ugly is because you're at the borderline of nice and clean C++ style code and nice and clean C style code. The C++ code uses iterators, the C code uses pointers and sizes.

它看起来难看的原因是因为你处于漂亮干净的 C++ 风格代码和漂亮干净的 C 风格代码的边界。C++ 代码使用迭代器,C 代码使用指针和大小。

You could create some glue to circumvent these problems:

您可以创建一些胶水来规避这些问题:

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

and call it in the client code.

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

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

回答by peterchen

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:

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

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

}

One could even add an implicit std::vectorconstructor to SizedPtr, but I wanted to avoid this dependency.

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

This helps only if callFunctionis 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.

只有callFunction在您的控制之下,这才有帮助。如果您在一个应用程序中使用不同的矢量类型并且想要合并,那么使用它是一种乐趣。如果您通常使用std::vector,那几乎毫无意义。

Roughly:

大致:

##代码##

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.

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

回答by Klaim

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.

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