Разумно ли использовать 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 при возврате значения.

Другие вопросы по тегам