[英]How do I cast `std::string` to `std::vector<unsigned char>` without making a copy?
There is a library function I want to call whose signature is: 我想调用一个库函数,其签名是:
bool WriteBinary(const std::vector<uint8_t> & DataToWrite);
I have an std::string
variable, I want to send it this function as argument. 我有一个
std::string
变量,我想把它作为参数发送给它。
void WriteString(const std::string & TextData)
{
// ...
WriteBinary(TextData); // <-- How to make this line work?
// ...
}
Is there a way I can directly send the std::string
variable without making a copy of it? 有没有办法可以直接发送
std::string
变量而不复制它?
There's no way to do this, because the layouts of the two types are not guaranteed to be similar in any way. 没有办法做到这一点,因为两种类型的布局不能保证以任何方式相似。
The best approach is to fix WriteBinary
to use "iterators" instead: 最好的方法是修改
WriteBinary
以使用“迭代器”:
bool WriteBinary(const unsigned char* first, const unsigned char* last);
Or template it: 或模板:
template <typename Iter>
bool WriteBinary(Iter first, Iter last);
And then you can use it for strings, vectors, or any other container you like! 然后你可以将它用于字符串,向量或任何其他你喜欢的容器!
Otherwise you can use the iterator constructor to do the copy as efficiently as possible: 否则,您可以使用迭代器构造函数尽可能高效地执行复制:
WriteBinary(std::vector<uint8_t>(TextData.begin(), TextData.end()));
I am afraid that is not possible. 我担心这是不可能的。 Neither
string
nor vector
has a constructor which would allow it to "adopt" a pre-existing buffer. string
和vector
都没有构造函数,允许它“采用”预先存在的缓冲区。 And it's very likely the memory layout of a string
and a vector
differ, so there is no casting possible. 并且
string
和vector
的内存布局很可能不同,因此无法进行转换。
Is there a way I can directly send the std::string variable without making a copy of it?
有没有办法可以直接发送std :: string变量而不复制它?
No, certainly not safely. 不,当然不安全。
If you have control over the library, I'd suggest a slight refactor. 如果您可以控制库,我建议稍微重构一下。
Either add: 要么添加:
template<typename CharT>
void WriteBinary(CharT const* buffer, size_t count);
Or: 要么:
template<typename FwdIter>
void WriteBinary(FwdIter begin, FwdIter end);
And then make your existing WriteBinary
and WriteString
call it: 然后让你现有的
WriteBinary
和WriteString
调用它:
void WriteBinary(std::vector<uint8_t> const& vec)
{ WriteBinary(&*vec.begin(), vec.size()); }
void WriteString(std::string const& s)
{ WriteBinary(&*s.begin(), s.size()); }
Or: 要么:
void WriteBinary(std::vector<uint8_t> const& vec)
{ WriteBinary(vec.begin(), vec.end()); }
void WriteString(std::string const& s)
{ WriteBinary(s.begin(), s.end()); }
Personally, I'd prefer the iterator based approach. 就个人而言,我更喜欢基于迭代器的方法。 It feels "cleaner".
感觉“更干净”。
(Note: for the pointer/size approach, you'd probably want to check for empty. Some implementations may assert if you deference the result of begin()
on an empty vector/string.) (注意:对于指针/大小方法,您可能希望检查是否为空。如果您在空向量/字符串上推断
begin()
的结果,则某些实现可能会断言。)
You are of course free to hack yourself through to obtain the desired result. 您当然可以自由地通过自己来获得所需的结果。 But you should prepare for a summary execution by co-workers or people wanting to use/maintain/modify or port your code...
但是您应该为同事或想要使用/维护/修改或移植代码的人准备摘要执行...
int main (void)
{
std::string teststring("HERE IS A TEST");
char * p = (char*)malloc(3*sizeof(char*) + sizeof(std::allocator<char>));
std::allocator< std::allocator<char> > alloc_alloc;
char * pa = p + 3*sizeof(char*);
alloc_alloc.construct((std::allocator<char>*)pa);
char const * cp = teststring.data();
char const * * vec_it = (char const**)p;
vec_it[0] = cp;
vec_it[1] = cp + teststring.length();
vec_it[2] = vec_it[1];
std::vector<char> &a_vector = *((std::vector<char, std::allocator<char>>*)p);
cout << a_vector.size() << " elements in vector!" << endl;
for (std::vector<char>::iterator i=a_vector.begin(); i!=a_vector.end(); ++i)
{
cout << *i;
}
cout << endl;
// set char 8 to 66 = B
a_vector[8] = 66;
cout << teststring << endl;
}
Prints 打印
14 elements in vector!
HERE IS A TEST
HERE IS B TEST
As correctly mentioned in the comments, this solution relys on the vector to have the following data layout and requires the string to store it's data contiguously (dunno whether this is predetermined by the standard). 正如评论中正确提到的,此解决方案依赖于向量具有以下数据布局,并且需要字符串连续存储其数据(不管这是否由标准预先确定)。
template <typename T>
class vector
{
T* _first, _last, _end;
std::allocator<T> _alloc;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.