Есть ли способ получить буфер std: string - PullRequest
14 голосов
/ 20 октября 2011

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

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

Так есть ли в std :: string нечто подобное?

Ответы [ 6 ]

16 голосов
/ 20 октября 2011

Используйте 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 .

15 голосов
/ 07 апреля 2013

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

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

Цитировать Херб Саттер ,

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

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

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

3 голосов
/ 20 октября 2011

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

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

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

1 голос
/ 13 ноября 2017

Согласно этой статье 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);
1 голос
/ 20 октября 2011

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

0 голосов
/ 20 октября 2011
 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);
...