C ++: правильная реализация для передачи std :: string функции C, которая хочет изменить строку? - PullRequest
7 голосов
/ 03 августа 2011

У меня есть функция в сторонней библиотеке, написанная на C: char* fix_filename_slashes(char* path). Эта функция ожидает, что ей будет передана изменяемая C-строка, чтобы она могла изменить все слэши в пути для правильного использования в зависимости от операционной системы. Все строки, которые я использую в своем Фасаде, объявлены как std::string s. Я попытался просто использовать foo.c_str(), поскольку любая другая функция, которая ожидает, что строка C не меняет ее, и ожидает const char *, но эта функция вызывает ошибку: Error: Argument of type "const char *" is incompatible with parameter of type "char *"

Является ли результат, который я придумал:

char* tempf = const_cast<char*>(filename.c_str());
filename = std::string(fix_filename_slashes(tempf));
tempf = NULL;

считается "правильным" или есть другие (более правильные?) Способы выполнения задачи?

EDIT

Whups. Видимо функция возвращает КОПИЮ строки. Тем не менее, есть некоторые хорошие ответы, которые уже даны.

Ответы [ 5 ]

7 голосов
/ 03 августа 2011

Если длина строки не изменяется, вы можете использовать указатель на первый символ строки.Это неопределенное поведение в стандарте C ++ 03, но все известные реализации работают должным образом, и это явно разрешено в соответствии со стандартом C ++ 11.

fix_filename_slashes(&filename[0]);

Если размер строки может измениться, выПридется еще немного поработать.

filename.resize(max_size, 0);
append_filename_suffix(&filename[0]);
filename.resize(strlen(filename.c_str()));
1 голос
/ 03 августа 2011

Поскольку вы решаете все проблемы, вы можете просто выполнить требования функции C и скопировать строку в массив char, а затем после функции создать строку из массива char или принудительно назначить копирование для исходной строки .

    char* temp = new char[str.size() + 1]
    // Force a copy of the result into another string
    str = (const char*)fix_filename_slashes(strncpy(temp, str.c_str(), str.size() + 1));
    delete [] temp;
1 голос
/ 03 августа 2011

Преобразовать его в последовательность символов с нулевым символом в конце, сохраненную в std::vector:

template <typename Character>
std::vector<Character> to_vector(std::basic_string<Character> const& s)
{
    std::vector<Character> v;
    v.reserve(s.size() + 1);
    v.insert(v.end(), s.begin(), s.end());
    v.push_back(0);
    return v;
}

Пример использования:

std::string filename = get_filename();
std::vector<char> filename_cstr = to_vector(filename);
filename = std::string(fix_filename_slashes(&filename_cstr[0]));
0 голосов
/ 03 августа 2011

Вот еще один подход, который требует небольшой настройки, но после этого работает автоматически. Он опирается на временный объект, который берет копию исходной строки и копирует измененную строку обратно в деструктор. Очевидно, что все это копирование не будет слишком эффективным, но в большинстве случаев эффективность не будет иметь значения.

class mutable_string
{
public:
    mutable_string(std::string & str, int maxlen = 0) : m_str(str)
    {
        m_buffer.resize(max(maxlen, str.length()) + 1);
        memcpy(&m_buffer[0], str.c_str(), str.length()+1);
    }
    ~mutable_string()
    {
        m_str = m_buffer;
    }
    operator char* ()
    {
        return &m_buffer[0];
    }
private:
    std::string &     m_str;
    std::vector<char> m_buffer;
};

fix_filename_slashes(mutable_string(filename));
0 голосов
/ 03 августа 2011

Если string использует отдельный буфер для хранения строки c_str, это не изменит исходную строку.

Лучше создать буфер char в стеке или куче, скопируйтесимволы в нем (завершенные нулем), вызвать функцию исправления, а затем назначить буфер обратно в строку.

...