Как я могу получить указатель на первый элемент std :: string, даже если он пуст - PullRequest
0 голосов
/ 11 сентября 2018

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

Я точно знаю, что строка имеет емкость больше единицы, однако, просто используя

&my_string.front()

запускает ошибку подтверждения «вне диапазона итератора», потому что строка пуста. Использование функции-члена

data()

тоже не подходит, потому что я хочу указатель типа char *, а не const char *. Я думаю, что я могу выполнить const_cast здесь, но это не кажется аккуратным.

Есть ли лучший способ сделать это?

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

Хотя front() будет выбрасывать здесь, my_string[my_string.size()] в настоящее время считается действительным & mdash; с этим ничего не поделаешь, но вы можете взять и сохранить его адрес (т. е. &my_string[0]).

Однако в этом есть только сомнительная ценность. Таким образом, вы, вероятно, можете предположить, что первая группа вставок символов (до текущей емкости) практически не сделает недействительным ваш указатель, но ваш код будет иметь неясную корректность, так как нам специально говорит строка . требовать, чтобы параграф 4 не полагался на него :

Ссылки, указатели и итераторы, ссылающиеся на элементы последовательности basic_­string, могут быть признаны недействительными из-за следующего использования этого объекта basic_­string:

  • в качестве аргумента любой стандартной библиотечной функции, принимающей в качестве аргумента ссылку на неконстантный basic_­string.
  • Вызов неконстантных функций-членов, кроме operator[], at, data, front, back, begin, rbegin, end и rend.

Так что на самом деле не гарантируется, что специальный «пустой» буфер, на который указывают, будет действительно тем же самым, который в конечном итоге будет использоваться для хранения реальной строки (хотя этот буфер также будет гарантированно завершен нулем таким же образом). Разумеется, когда вы превысили объем, все ставки полностью прекратились, и вы действительно хотите отслеживать это событие?

Это действительно звучит так, как будто std::string - это не то, что вам нужно, или что вы должны обращаться к data() как и когда вместо того, чтобы вызывать его один раз, чтобы сохранить полученный указатель.

Если вы взаимодействуете с каким-то C API, который должен хранить этот указатель, я бы переключился на что-то другое, возможно, на символьный буфер фиксированной длины. На стороне C ++ вы все еще можете использовать std::string_view, чтобы доставлять удовольствие (только для чтения) вещам с вашим C-подобным буфером символов, так что вы не потеряете ничего из этого.

#include <string_view>
#include <iostream>

void OkayCApiStoreThisThen(const char*) {}

static constexpr const size_t BUF_SIZE = 255;
char silly_buf[BUF_SIZE] = {};

int main()
{
    // Sadface
    OkayCApiStoreThisThen(silly_buf);

    // Happyface
    std::string_view str(silly_buf, sizeof(silly_buf));

    silly_buf[0] = 'l';
    silly_buf[1] = 'o';
    silly_buf[2] = 'l';
    silly_buf[3] = '!';

    std::cout << str.substr(0, 3) << '\n';
}
0 голосов
/ 11 сентября 2018

Чтобы получить string::data(), возвращающий char*, вам, к сожалению, необходимо перейти на C ++ 17. const_cast'ing результат data() может быть приемлемым вариантом, если вам действительно нужен доступ на запись к базовым данным.

...