直接写入std :: string内部缓冲区

mar*_*h44 34 c++ string

我正在寻找一种方法将一些数据填充到DLL边界的字符串中.因为我们使用不同的编译器,所有的dll接口都是简单的char*.

是否有正确的方法将指针传递给dll函数,以便它能够直接填充字符串缓冲区?

string stringToFillIn(100, '\0');
FunctionInDLL( stringToFillIn.c_str(), stringToFillIn.size() );   // definitely WRONG!
FunctionInDLL( const_cast<char*>(stringToFillIn.data()), stringToFillIn.size() );    // WRONG?
FunctionInDLL( &stringToFillIn[0], stringToFillIn.size() );       // WRONG?
stringToFillIn.resize( strlen( stringToFillIn.c_str() ) );
Run Code Online (Sandbox Code Playgroud)

看起来最有希望的是&stringToFillIn [0]但是这是一个正确的方法,假设你认为string :: data()==&string [0]?这似乎不一致.

或者最好是吞下额外的分配并避免问题:

vector<char> vectorToFillIn(100);
FunctionInDLL( &vectorToFillIn[0], vectorToFillIn.size() );
string dllGaveUs( &vectorToFillIn[0] );
Run Code Online (Sandbox Code Playgroud)

CAd*_*ker 24

我不确定标准是否保证a中的数据std::string存储为char*.我能想到的最便携的方法是使用a std::vector,保证将其数据存储在连续的内存块中:

std::vector<char> buffer(100);
FunctionInDLL(&buffer[0], buffer.size());
std::string stringToFillIn(&buffer[0]);
Run Code Online (Sandbox Code Playgroud)

这当然需要将数据复制两次,这有点效率低下.

  • 在效率方面,如果你开始使用std :: vector作为缓冲区,你将遇到另一种性能问题,其中向量的每个元素都是逐个初始化的.如果您保留32K缓冲区(并不是那么多),您将花费大量的CPU时间来初始化此缓冲区.如果你只需要一个连续的内存块,你就可以简单地使用一个数组新的char []与std :: unique_ptr或其他一些RAII模式的组合,你很高兴但是不要使用std :: vector除非你绝对需要初始化每个元素. (7认同)
  • 使用http://stackoverflow.com/questions/11149665/c-vector-that-doesnt-initialize-its-members中的vector <uninitialized_char>技巧. (2认同)
  • “我不确定标准是否保证 `std::string` 中的数据存储为 `char*`。” 这是有保证的。`std::string` 使用 `char`。http://en.cppreference.com/w/cpp/string/basic_string (2认同)

mar*_*h44 18

经过更多阅读和挖掘之后,我发现string :: c_str和string :: data可以合法地返回一个指向缓冲区的指针,该缓冲区与字符串本身的存储方式无关.例如,字符串可能存储在段中.写入这些缓冲区对字符串的内容有不确定的影响.

另外,string :: operator []不应该用于获取指向字符序列的指针 - 它应该只用于单个字符.这是因为指针/数组的等价不适用于字符串.

对此非常危险的是,它可以在某些实现上工作,但在未来的某个日期突然中断,没有明显的原因.

因此,正如其他人所说的那样,唯一安全的方法是避免任何尝试直接写入字符串缓冲区并使用向量,将指针传递给第一个元素,然后从向量返回的向量中分配字符串. DLL功能.

  • C++ 0x正在改变字符串以使用连续内存 (34认同)
  • Patrick说的是什么.此外,Herb Sutter在2008年与C++ 0x工作组讨论此事时,并不知道一个不连续的实现:http://herbsutter.wordpress.com/2008/04/07/cringe-not-vectors-are-guarantee-to-contiguous /(并向下滚动到评论). (2认同)

And*_*tan 9

在C++ 98你不应该改变由返回的缓冲区string::c_str()string::data().另外,正如其他答案中所解释的那样,你不应该使用它string::operator[]来获取指向一系列字符的指针 - 它应该只用于单个字符.

从C++ 11开始,字符串使用连续的内存,因此您可以使用&string[0]访问内部缓冲区.


Bri*_*aak 5

只要C ++ 11提供连续的内存保证,在生产实践中,这种“ hacky”方法就很受欢迎:

std::string stringToFillIn(100, 0);
FunctionInDLL(stringToFillIn.data(), stringToFillIn.size());
Run Code Online (Sandbox Code Playgroud)

  • 为了扩展Brian的评论,C ++ 17添加了一个非const`data()`替代,专门允许此行为。 (3认同)