Разумно ли использовать std::basic_string<t> в качестве непрерывного буфера при нацеливании на C++03?
Я знаю, что в C++03 технически std::basic_string
Шаблон не обязательно должен иметь непрерывную память. Тем не менее, мне любопытно, сколько существует реализаций для современных компиляторов, которые фактически используют эту свободу. Например, если кто-то хочет использовать basic_string
чтобы получить результаты некоторого C API (как пример ниже), кажется глупым выделять вектор, чтобы сразу превратить его в строку.
Пример:
DWORD valueLength = 0;
DWORD type;
LONG errorCheck = RegQueryValueExW(
hWin32,
value.c_str(),
NULL,
&type,
NULL,
&valueLength);
if (errorCheck != ERROR_SUCCESS)
WindowsApiException::Throw(errorCheck);
else if (valueLength == 0)
return std::wstring();
std::wstring buffer;
do
{
buffer.resize(valueLength/sizeof(wchar_t));
errorCheck = RegQueryValueExW(
hWin32,
value.c_str(),
NULL,
&type,
&buffer[0],
&valueLength);
} while (errorCheck == ERROR_MORE_DATA);
if (errorCheck != ERROR_SUCCESS)
WindowsApiException::Throw(errorCheck);
return buffer;
Я знаю, что такой код может немного уменьшить переносимость, потому что это означает, что std::wstring
является смежным, но мне интересно, насколько непереносимым, что делает этот код. Другими словами, как компиляторы могут на самом деле воспользоваться свободой, которую позволяет несмежная память?
РЕДАКТИРОВАТЬ: я обновил этот вопрос, чтобы упомянуть C++03. Читатели должны заметить, что при ориентации на C++11 стандарт теперь требует, чтобы basic_string
быть смежным, поэтому вышеупомянутый вопрос не является проблемой при нацеливании на этот стандарт.
5 ответов
Я считаю вполне безопасным предположить, что std::string выделяет свое хранилище непрерывно.
В настоящее время все известные реализации std::string
выделять пространство непрерывно.
Кроме того, текущий проект C++ 0x ( N3000) [Правка: Предупреждение, прямая ссылка на большой PDF] требует, чтобы пространство выделялось непрерывно (§21.4.1/5):
Символоподобные объекты в объекте basic_string должны храниться непрерывно. То есть для любого объекта s basic_string тождество &*(s.begin() + n) == &*s.begin() + n должно выполняться для всех значений n, таких что 0 <= n
Таким образом, шансы на текущую или будущую реализацию std::string
использование несмежного хранилища по существу равно нулю.
Некоторое время назад возник вопрос о возможности записи в хранилище для std::string
как если бы это был массив символов, и это зависело от того, является ли содержимое std::string
были смежными:
Мой ответ показал, что согласно паре хорошо известных источников (Херб Саттер и Мэтт Аустерн) текущий стандарт C++ требует std::string
хранить свои данные непрерывно при определенных условиях (как только вы позвоните str[0]
при условии, str
это std::string
) и что этот факт в значительной степени заставляет руку любой реализации.
В основном, если вы объедините обещания string::data()
а также string::operator[]()
вы пришли к выводу, что &str[0]
должен вернуть непрерывный буфер. Поэтому Аустерн предлагает, чтобы комитет просто сделал это явным, и, очевидно, именно это произойдет в стандарте 0x (или они сейчас называют это стандартом 1x?).
Строго говоря, реализация не должна реализовывать std::string
использование смежного хранилища, но оно должно выполняться по требованию. И ваш пример кода делает это, передавая &buffer[0]
,
Ссылки:
Изменить: Вы хотите позвонить &buffer[0]
не buffer.data()
, так как []
возвращает не const
ссылка и уведомляет объект о том, что его содержимое может неожиданно измениться.
Было бы чище сделать buffer.data()
, но вам следует меньше беспокоиться о непрерывной памяти, чем о памяти, разделяемой между структурами. string
Реализации могут и будут ожидать, когда будут сообщены, когда объект изменяется. string::data
в частности, требует, чтобы программа не изменяла возвращаемый внутренний буфер.
ОЧЕНЬ высоки шансы, что в какой-то реализации будет создан один буфер для всех неинициализированных строк, кроме того, если длина установлена в 10 или что-то еще
Использовать vector
или даже массив с new[]
/ delete[]
, Если вы действительно не можете скопировать буфер, юридически инициализируйте строку во что-то уникальное перед ее изменением.
Результат не определен, и я бы не стал этого делать. Стоимость чтения в вектор с последующим преобразованием в строку в современных кучах C++ тривиальна. VS риск того, что ваш код умрет в Windows 9
также, разве это не требует const_cast на &buffer[0]?
Конечно, выделять вектор здесь глупо. Использование std::wstring здесь также нецелесообразно. Лучше использовать массив char для вызова winapi. построить wstring при возврате значения.