Как передать std::string функции, ожидающей char *?

Возможный дубликат:Можно ли получить строку non-const C из строки С++?

Нужно ли сначала его преобразовать? Я видел в другом сообщении, что .c_str() может использоваться, если функция ожидается const char *. Как насчет только char *?

6 ответов

std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());
</char>


Невозможно получить char * из строки, которая, как гарантируется, будет работать на всех платформах, поскольку тот факт, что string не требуется использовать непрерывное хранилище.

Ваш самый безопасный, самый переносимый курс действий - это скопировать строку где-нибудь, где используется условное хранилище (возможно, vector), и использовать это вместо этого.

vector<char> chars(my_string.begin(), my_string.end());
char* ptr = &chars[0];
</char>

Если вы хотите быть взломанным и не переносным и явно небезопасным, вы можете подтвердить, что ваша реализация string действительно использует условное хранилище, а затем, возможно, использует это:

&my_str[0]

Но я бы ударил любого разработчика, который работал у меня, который сделал это.

EDIT:

Мне сообщили, что в настоящее время нет известных реализаций STL, которые не хранят строковые данные в смежном массиве, что сделало бы &my_str[0] безопасным. Также верно (и мне было предложено это указать), что в предстоящем стандарте С++ 0x потребуется, чтобы хранилище было смежным.

Было высказано предположение, что, если эти факты говорят о том, что мой пост фактически неверен.

Решите для себя, но я говорю "нет". Это не в текущем стандарте С++, и поэтому это не требуется. Я по-прежнему буду на практике делать то, что я предложил, и в любом обзоре кода я буду отмечать любой код, который предполагает, что базовое хранилище является условным.

Рассмотрим это. Предположим, что возник вопрос о указателях vtable. Кто-то хочет изучить класс и получить указатель на виртуальную функцию, посмотрев на таблицу vtable. Я бы сразу сказал им не делать этого, потому что не упоминается, как виртуальные методы реализованы на С++. Каждая реализация, которую я знаю, использует vtables, и я не могу придумать лучшего способа сделать это. Вполне вероятно, что полиморфизм навсегда будет реализован с использованием vtables. Означает ли это, что можно проверить непосредственно виртуальную таблицу?

IMO нет, потому что это зависит от деталей недокументированной реализации. У вас нет контроля над этим, и он может измениться в любое время. Даже если вы ожидаете, что это никогда не изменится, все еще плохой инженер должен полагаться на эти детали реализации.

Решите для себя.


Если вы уверены, что char * не будет изменен, вы можете использовать const_cast, чтобы удалить константу.


Это грязное решение, но я думаю, он работает

std::string foo("example");

char* cpy = (char*)malloc(foo.size()+1);

memcpy(cpy, foo.c_str(), foo.size()+1);


Когда параметр объявлен как char *, подразумевается, что функция будет иметь в качестве побочного эффекта модификацию указанной строки. Основываясь на этом и на том факте, что c_str() не допускает модификаций вложенной строки, вы не можете явно передать этот метод std::string.

Что-то вроде этого может быть достигнуто, следуя следующему подходу:

#include <cstdlib>
#include <string>
#include <iostream>
void modify_string(char* pz)
{
 pz[0] = 'm';
}
class string_wrapper
{
 std::string& _s;
 char* _psz;
 string_wrapper(const string_wrapper&);
 string_wrapper& operator=(const string_wrapper&);
public:
 string_wrapper(std::string& s) : _s(s), _psz(0) {}
 virtual ~string_wrapper()
 {
 if(0 != _psz)
 {
 _s = _psz;
 delete[] _psz;
 }
 }
 operator char*()
 {
 _psz = new char[_s.length()+1];
 strcpy(_psz,_s.c_str());
 return _psz;
 }
};
int main(int argc, char** argv)
{
 using namespace std;
 std::string s("This is a test");
 cout << s << endl;
 modify_string(string_wrapper(s));
 cout << s << endl;
 return 0;
}
</iostream></string></cstdlib>


Существует три сценария:

Если функция находится вне вашего контроля, и она либо изменяет строку, либо вы не знаете и не можете знать, изменяет ли она строку:

Затем скопируйте строку во временный буфер и передайте ее функции, например:

void callFoo(std::string& str);
{
 char* tmp = new char str(str.length() +1);
 strncpy(tmp, str.c_str(), str.length());
 foo(tmp);
 // Include the following line if you want the modified value:
 str = tmp;
 delete [] tmp;
}

Если функция находится вне вашего контроля, но вы определенная, она не модифицирует строку и что не принимать аргумент как const - это просто ошибка в части API.

Затем вы можете отбросить const и передать это функции

void callFoo(const std::string& str)
{
 foo(const_cast<char*> str.c_str());
}
</char*>

Вы контролируете функцию (и это не будет чрезмерно разрушительно для изменения подписи).

В этом случае измените функцию, чтобы принять либо string& (если он изменяет входной буфер), либо либо const char*, либо const string&, если это не так.

licensed under cc by-sa 3.0 with attribution.