简体   繁体   English

如何将`std :: string`转换为`std :: vector <unsigned char> `没有复制?

[英]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. stringvector都没有构造函数,允许它“采用”预先存在的缓冲区。 And it's very likely the memory layout of a string and a vector differ, so there is no casting possible. 并且stringvector的内存布局很可能不同,因此无法进行转换。

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: 然后让你现有的WriteBinaryWriteString调用它:

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... 但是您应该为同事或想要使用/维护/修改或移植代码的人准备摘要执行...

... don't do it!... ......不要这样做!......

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

Note: 注意:

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.

相关问题 我该如何投射一个std :: vector <const unsigned char> 到const std :: vector <unsigned char> ? - How can I cast an std::vector<const unsigned char> to a const std::vector<unsigned char>? Cast const std :: vector <char> 到unsigned char *? - Cast const std::vector<char> to unsigned char*? 如何将 std::string 复制到无符号字符数组? - How to copy a std::string to unsigned char array? 如何转换std :: vector <unsigned char> 矢量 <char> 没有复制? - How to convert std::vector<unsigned char> to vector<char> without copying? 如何将具有十六进制值的 std::string 转换为 std::vector<unsigned char></unsigned> - How to convert std::string with hex values into std::vector<unsigned char> 如何在没有reinterpret_cast的情况下将unsigned char转换为std :: string? - Way to get unsigned char into a std::string without reinterpret_cast? 将向量std :: string转换为char *** - Cast a vector of std::string to char*** 如何在没有强制转换或复制的情况下从 const unsigned char* 初始化 std::istringstream? - How to initialise std::istringstream from const unsigned char* without cast or copy? std ::在std :: string和std :: vector之间移动<unsigned char> - std::move between std::string and std::vector<unsigned char> 给定一个填充无符号字符**的 C 函数,如何在没有中间副本的情况下使用数据填充 std::vector - Given a C function that populates a unsigned char**, how to populate a std::vector with the data without an intermediate copy
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM