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
How to get the address of the std::vector buffer start most elegantly?
提问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 buffer
is 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 NULL
should 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 callFunction
or 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::vector
constructor to SizedPtr
, but I wanted to avoid this dependency.
甚至可以向 中添加一个隐式std::vector
构造函数SizedPtr
,但我想避免这种依赖。
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.
只有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] 是标准保证的唯一获取向量缓冲区地址的方法。