7

我想调用一个库函数,其签名是:

bool WriteBinary(const std::vector<uint8_t> & DataToWrite);

我有一个std::string变量,我想将此函数作为参数发送给它。

void WriteString(const std::string & TextData)
{
    // ...
    WriteBinary(TextData);  // <-- How to make this line work?
    // ...
}

有没有办法直接发送std::string变量而不复制它?

4

4 回答 4

11

没有办法做到这一点,因为这两种类型的布局不能保证以任何方式相似。

最好的方法是WriteBinary改用“迭代器”:

bool WriteBinary(const unsigned char* first, const unsigned char* last);

或模板:

template <typename Iter>
bool WriteBinary(Iter first, Iter last);

然后你可以将它用于字符串、向量或任何其他你喜欢的容器!

否则,您可以使用迭代器构造函数尽可能高效地进行复制:

WriteBinary(std::vector<uint8_t>(TextData.begin(), TextData.end()));
于 2013-05-16T19:28:11.030 回答
5

恐怕这是不可能的。既没有string也没有vector允许它“采用”预先存在的缓冲区的构造函数。并且很可能 astring和 a的内存布局vector不同,因此无法进行强制转换。

于 2013-05-16T19:23:02.803 回答
2

有没有办法可以直接发送 std::string 变量而不复制它?

不,当然不安全。

如果您可以控制该库,我建议您进行轻微的重构。

要么添加:

template<typename CharT>
void WriteBinary(CharT const* buffer, size_t count);

或者:

template<typename FwdIter>
void WriteBinary(FwdIter begin, FwdIter end);

然后让你存在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()); }

或者:

void WriteBinary(std::vector<uint8_t> const& vec)
{ WriteBinary(vec.begin(), vec.end()); }

void WriteString(std::string const& s)
{ WriteBinary(s.begin(), s.end()); }

就个人而言,我更喜欢基于迭代器的方法。感觉“更干净”。

(注意:对于指针/大小方法,您可能想要检查是否为空。如果您尊重begin()空向量/字符串的结果,某些实现可能会断言。)

于 2013-05-16T19:43:10.747 回答
1

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;
};
于 2013-05-16T19:58:26.507 回答