Есть ли способ получить буфер std: string

есть ли способ получить" сырой " буфер o std:: string?
Я думаю о чем-то похожем на CString::GetBuffer(). Например, с помощью CString я бы сделал:

CString myPath;  
::GetCurrentDirectory(MAX_PATH+1, myPath.GetBuffer(MAX_PATH));  
myPath.ReleaseBuffer();  

итак, имеет ли std:: string что-то подобное?

6 ответов


использовать std::vector<char> Если вам нужен настоящий буфер.

#include <vector>
#include <string>

int main(){
  std::vector<char> buff(MAX_PATH+1);
  ::GetCurrentDirectory(MAX_PATH+1, &buff[0]);
  std::string path(buff.begin(), buff.end());
}

пример на Ideone.


В то время как немного неортодоксально, это совершенно правильно использовать std::string в качестве линейного буфера памяти единственное предостережение заключается в том, что он не поддерживается стандартом до C++11.

std::string s;
char* s_ptr = &s[0]; // get at the buffer

цитата Херб Саттер,

каждая реализация std:: string, о которой я знаю, на самом деле непрерывна и null-завершает свой буфер. Так что, хотя формально это не так гарантировано, на практике вы, вероятно, можете уйти с вызовом &str[0] чтобы получить указатель на непрерывная и завершенная нулем строка. (А будьте осторожны, вы все равно должны использовать str.c_str().)

вероятно, является ключевым здесь. Таким образом, хотя это и не гарантия, вы должны иметь возможность полагаться на принцип, что std::string является линейным буфером памяти, и вы должны утверждать факты об этом в своем наборе тестов, чтобы быть уверенным.

вы всегда можете создать свой собственный класс буфера, но когда вы хотите купить, это то, что может предложить STL.


не переносимо, нет. Стандарт не гарантирует, что std::strings имеют исключительное линейное представление в памяти (и со старым стандартом C++03 разрешены даже структуры данных, такие как веревки), поэтому API не дает вам доступа к нему. Они должны иметь возможность изменять свое внутреннее представление на это (в C++03) или предоставлять доступ к своему линейному представлению (если оно у них есть, что применяется в C++11), но только для чтения. Вы можете получить доступ к этому, используя data() и/или c_str(). Из-за этого интерфейс по-прежнему поддерживает копирование при записи.

обычная рекомендация для работы с C-API, которые изменяют массивы путем доступа через указатели, - использовать std::vector, который гарантированно имеет линейное представление памяти именно для этой цели.

чтобы подвести итог: если вы хотите сделать это переносимо и если вы хотите, чтобы ваша строка оказалась в std::string, У вас нет выбора, кроме как скопировать результат в строку.


Это c_str, который во всех реализациях C++, которые я знаю, возвращает базовый буфер (но как const char *, Так что вы не можете изменить его).


 std::string str("Hello world");
 LPCSTR sz = str.c_str();

имейте в виду, что sz будет признан недействительным, когда str перераспределяется или выходит за рамки. Вы можете сделать что-то вроде этого, чтобы отделиться от строки:

 std::vector<char> buf(str.begin(), str.end()); // not null terminated
 buf.push_back(0); // null terminated

или в старомодном стиле C (обратите внимание, что это не позволит строкам со встроенными нулевыми символами):

 #include <cstring>

 char* sz = strdup(str.c_str());

 // ... use sz

 free(sz);

согласно этой статье MSDN, Я думаю, это лучший подход для того, что вы хотите сделать, используя std::wstring напрямую. Второй лучший std::unique_ptr<wchar_t[]> и третий использует std::vector<wchar_t>. Не стесняйтесь читать статью и делать собственные выводы.

// Get the length of the text string
// (Note: +1 to consider the terminating NUL)
const int bufferLength = ::GetWindowTextLength(hWnd) + 1;
// Allocate string of proper size
std::wstring text;
text.resize(bufferLength);
// Get the text of the specified control
// Note that the address of the internal string buffer
// can be obtained with the &text[0] syntax
::GetWindowText(hWnd, &text[0], bufferLength);
// Resize down the string to avoid bogus double-NUL-terminated strings
text.resize(bufferLength - 1);