Функция как для строк в стиле C, так и для c ++ std :: string

0

У меня есть функция, которая управляет строкой, и мне нужно, чтобы она работала как в строках C-стиля, так и в C++ std :: string:

// C-style overload
void TransformString(const char *in_c_string, char *out_string);
// C++ std::strings overload
std::string TransformString(const std::string &in_string);

Чтобы избежать избыточного кода, я могу реализовать фактический алгоритм только в одном из них, а затем вызвать его другим. Итак, если поставить реализацию в C++ перегруженной функции, то функция C-стиля будет выглядеть так:

void TransformString(const char *in_c_string, char * out_c_string) {
   std::string in_string(in_c_string);
   std::string out_string = TransformString(in_string); // call C++ std::string overload
   strcpy(out_c_string, out_string.c_str()); // unwanted memory copy
}

Мой вопрос: могу ли я сделать это (имея алгоритм, реализованный только в одной функции) без дополнительной копии (из внутреннего буфера std::string в строку стиля C)? Моя первая мысль заключалась в том, чтобы попытаться "украсть" буфер, как это делает конструктор перемещения строки, но при поиске в Интернете кажется, что нет безопасного способа сделать это, поскольку он специфичен для реализации. И если я напишу алгоритм в функции C-стиля, проблема будет такой же, как в функции C++, я должен выделить пространство для строки char*, а затем переместить его в объект std::string.
Я должен упомянуть, что я не знаю размер результирующей строки до завершения преобразования.

Спасибо.

РЕДАКТИРОВАТЬ

Размер буфера здесь не проблема (я знаю максимальный размер, и функция получает выделенный буфер). Я не могу просто вернуть std :: string.c_str(), потому что тогда буфер станет недействительным, когда объект std :: string будет уничтожен (сразу после возврата). Я изменил имя переменной out_c_string. (спасибо 0x499602D2)

  • 0
    Поскольку размер вывода заранее не известен, вызывающая сторона не может выделить память для результата. Тогда я не понимаю, как ваша перегрузка в стиле C может работать. Вам понадобится char **out_string в качестве второго параметра (или просто верните char * )
  • 0
    У вас есть две переменные с именем out_string в вашем примере.
Показать ещё 4 комментария
Теги:
string
buffer
move-semantics

2 ответа

2
Лучший ответ

До тех пор, пока вы знаете, насколько большой буфер вывода должен быть, вы можете создать std::string и изменить его размер до размера буфера. Затем вы можете передать указатель на std::string buffer в перегрузку C-стиля.

#include <cstring>
#include <iostream>
#include <string>

void TransformString(const char *in_c_string, char *out_c_string) {
    size_t length = strlen(in_c_string);

    for (size_t i = 0; i < length; ++i)
        out_c_string[i] = '*';

    out_c_string[length] = 'a';
    out_c_string[length+1] = 'b';
    out_c_string[length+2] = 'c';
    out_c_string[length+3] = '\0';
}

std::string TransformString(const std::string &in_string) {
    std::string out;
    out.resize(100);

    TransformString(in_string.c_str(), &out[0]);
    out.resize(strlen(&out[0]));

    // IIRC there are some C++11 rule that allows 'out' to
    // be automatically moved here (if it isn't RVO'd)
    return out;
}

int main() {
    std::string string_out = TransformString("hello world");

    char charstar_out[100];
    TransformString("hello world", charstar_out);

    std::cout << string_out << "\n";
    std::cout << charstar_out << "\n";

    return 0;
}

Вот живой пример: http://ideone.com/xwVWCh.

  • 0
    Это имеет те же проблемы, что и предложение c_str: это UB, чтобы изменить внутренние данные std :: string. (Тот факт, что это «кажется, работает» не имеет значения.)
  • 1
    @rici этот код хорошо в C ++ 11.
Показать ещё 5 комментариев
-2

Вы можете попытаться получить строку стиля c из строкового класса с помощью c_str(). Вам нужно будет сделать const_cast<char*> чтобы удалить const_cast<char*>.

Это будет работать, только если вам не нужно перераспределять строку (сохраняйте тот же размер).

  • 3
    Это UB, и это может иметь катастрофические последствия для реализаций стандартной библиотеки, которые выполняют копирование при записи (хотя их меньше, чем раньше).
  • 0
    Нет, потому что буфер становится недействительным, когда уничтожается объект std :: string.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню