Можно ли использовать std:: basic_string <t> в качестве непрерывного буфера при таргетинге на С++ 03?

Я знаю, что в С++ 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 является смежным - но мне интересно, насколько unportable делает этот код. Иными словами, как могут компиляторы использовать преимущества свободы с несмежной памятью?


EDIT: я обновил этот вопрос, чтобы упомянуть С++ 03. Читатели должны учитывать, что при таргетинге на С++ 11 стандарт теперь требует, чтобы basic_string был смежным, поэтому вышеупомянутый вопрос не является проблемой при таргетинге на этот стандарт.

Ответ 1

Я бы с уверенностью считал, что std::string распределяет его хранилище соприкосновенно.

В настоящее время все известные реализации std::string распределяют пространство смежно.

Кроме того, текущий черновик С++ 0x (N3000) [Edit: Warning, прямая ссылка на большой PDF] требует, чтобы пространство распределяться смежно (§21.4.1/5):

char -подобные объекты в Объект basic_string должен быть сохранен смежно. То есть для любого basic_string object s, тождество & * (s.begin() + n) == & * s.begin() + n имеет место для всех значений n таких что 0 <= n < s.size().

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

Ответ 2

В то время как возник вопрос о возможности записи в хранилище для std::string, как если бы это был массив символов, и он зависел от того, было ли содержимое a std::string смежным:

Мой ответ показал, что согласно паре хорошо известных источников (Herb Sutter и Matt Austern) текущий С++-стандарт требует, чтобы std::string сохранял свои данные смежными при определенных условиях (как только вы вызываете str[0], предполагая, что str a std::string) и что этот факт в значительной степени заставляет руку любой реализации.

В принципе, если вы объедините promises, сделанный string::data() и string::operator[](), вы заключаете, что &str[0] должен возвращать непрерывный буфер. Поэтому Аустерн предполагает, что комитет просто делает это явным и, видимо, что произойдет в стандарте 0x (или они теперь называют его стандартом 1x?).

Так что, строго говоря, реализация не должна реализовывать std::string, используя непрерывное хранилище, но она должна делать это в значительной степени по требованию. И ваш пример кода делает это, передавая в &buffer[0].

Ссылки:

Ответ 3

Результат undefined, и я бы этого не сделал. Стоимость чтения в вектор и преобразование в строку тривиально в современных кубах С++. VS риск того, что ваш код умрет в Windows 9

также, не нужен ли const_cast on & buffer [0]?

Ответ 4

Изменить: Вы хотите вызвать &buffer[0], а не buffer.data(), потому что [] возвращает ссылку не const и уведомляет объект о том, что его содержимое может неожиданно измениться.


Было бы проще сделать buffer.data(), но вы должны меньше беспокоиться о непрерывной памяти, чем память, разделяемая между структурами. Реализации string могут и нужно ожидать, когда объект будет изменен. string::data специально требует, чтобы программа не изменяла возвращаемый внутренний буфер.

ОЧЕНЬ высокие шансы, что некоторая реализация создаст один буфер для всех строк без инициализации, кроме того, что длина равна 10 или что-то еще.

Используйте vector или даже массив с new[]/delete[]. Если вы действительно не можете скопировать буфер, законно инициализируйте строку до чего-то уникального, прежде чем изменять ее.

Ответ 5

Конечно, выделение вектора здесь глупо. Использование std:: wstring здесь также неразумно. Лучше использовать массив char для вызова winapi. постройте wstring при возврате значения.