2014-11-13 2 views
1

Это не дубликат чего-то типа «почему простой system(variable) не работает».Использовать переменную как вход system() WITHOUT c_str() в C++

решение для этого одного было бы просто хранить строку переменной ConverTable по c_str(), а затем просто позвонить: system(variable.c_str())

Однако я ищу способ сделать это без c_str()прямого вызова.

Так что я пытался что-то вроде

class systemRunner{ 
    private: 
     stringstream prepareStream; 
    public: 
     void setProgram(string s){ 
      prepareStream.str(""); // empty stream 
      prepareStream.clear(); // reset stream - !IMPORTANT! 
      prepareStream << "\"" << s << "\""; 
     } 
     void appendParam(string s){ this->prepareStream << " " << s; } 
     void appendParam(int i){ this->prepareStream- << " " << i; } 
     const char* getSystemRunCString(){ 
      //const std::string s = ; 
      return this->prepareStream.str().c_str(); 
     } 

}; 

можно было бы потом думать, что это будет enaugh:

system (systemRunner->getSystemRunCString()) 

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

Однако, когда я его восстанавливаю и использую c_str() в прямом системном вызове, например. например:

string tmp = (string)systemRunner->getSystemRunCString(); 
system(tmp.c_str()); 

Это прекрасно работает.

Можно было бы ожидать, что если создать метод, который возвращает то же самое, как c_str(),
, который const char*, что я хотел бы получить тот же результат, но я не получаю его ...

Я даже пытался поместить оба входа не в system(), а в файл - те же результаты, поэтому он хранит ту же информацию ...

Я что-то упустил? Возможно ли это?


PS: Я говорю об использовании system() в ОС Windows 7 приложения консоли ...

EDIT: Ну @ravi прямо о том, что вызывает этот пример на провал - но как насчет ответ на главный вопрос - в заголовке - можно ли вызвать систему (переменную) без прямого вызова c_str()? :)

+2

Вы использовали временный объект после его уничтожения. Это обычный дубликат ... – Deduplicator

+1

Возможный дубликат [Можно ли использовать (str1 + str2) .c \ _str()?] (Http://stackoverflow.com/questions/18146267/is-it-safe- to-use-str1-str2-c-str) – Deduplicator

+1

Почему ваш 'systemRunner' не« запускает »' систему' с его именем? Просто сохраните строку в качестве переменной-члена и вызовите функцию-член 'system'. – rubenvb

ответ

3

@ravi прекрасно объяснил, почему код не работает, поскольку значение, возвращаемое str(), выходит за пределы области видимости, но поскольку в комментариях упоминается, что до сих пор неясно, как решить актуальную проблему, возможный ответ:

class systemRunner{ 
    private: 
     string systemCommand; 
    public: 
     void setProgram(string s){ 
      systemCommand.clear(); 
      systemCommand.append("\"").append(s).append("\""); 
     } 
     void appendParam(string s){ systemCommand.append(" ").append(s); } 
     void appendParam(int i){ 
      // VS 2013: 
      // systemCommand.append(" ").append(to_string(i))); 
      // VS 2010: 
      // systemCommand.append(" ").append(to_string(static_cast<long long>(i))); 
      // General stringstream conversion 
      stringstream argumentStream; 
      argumentStream << i; 
      systemCommand.append(" ").append(argumentStream.str()); 
     } 

     const char* getSystemRunCString(){ 
      return systemCommand.c_str(); 
     } 

}; 

Используйте string вместо stringstream так, то указатель, возвращаемый c_str() будет действовать до тех пор, как экземпляр systemRunner не разрушается. Кроме того, для такого простого форматирования, как в вашем примере, вам не нужен stringstream, вы можете просто использовать методы append() и to_string().

+0

проверено, работает, спасибо за ответ на вопрос-ответ :) –

5
return this->prepareStream.str().c_str(); 

будет возвращен const char *. Этот указатель будет указателем на внутренний указатель символов, используемый классом string. Благодаря этой операции вы получите доступ к этим внутренним данным строки, но поскольку это указатель const, вы не сможете изменить его содержимое.

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

Вы никогда не должны полагаться на это.

+0

Думаю, я вижу вашу точку зрения, но как это отвечает на мой вопрос? :) –

+2

Это отвечает на вопрос: «Я что-то упустил?» –

+0

На самом деле prepareStream.str() возвращает * копию * своей внутренней строки, поэтому 'c_str()' вызывается на временную строку, которая сразу же уничтожается. Итак, 'string tmp = (string) systemRunner-> getSystemRunCString();' также является UB. –

2

Пока systemRunner сам не временный объект, вы можете сделать следующее:

class systemRunner { 
    private: 
     stringstream prepareStream; 
     string commandLine; 
    public: 
     //... 
     const char* getSystemRunCString() { 
      commandLine = prepareStream.str(); 
      return commandLine.c_str(); 
     } 
}; 

Таким образом, вы возвращает указатель не на временную строку, а в строке, которая имеет такой же срок службы, systemRunner объект.

Примечание хотя, что getSystemRunCString() следует использовать только в качестве поставщика для «временных» строк, вы никогда не должны использовать его как:

const char* cmd1 = runner.getSystemRunCString(); 
runner.setProgram(...); 
const char* cmd2 = runner.getSystemRunCString(); 
// cmd1 is now invalid. 
system(cmd1); // UB 

Это относится и к ответу Рудольфа Бундулис, а также.

+0

нет, см. Здесь у нас есть случайная строка, хранящаяся в экземпляре, по-видимому, без причины. – thecoshman

+0

@ jave.web это абсолютно отличный от вашего примера –

+1

@AntonSavin вы ничего не делали, кроме почтового кода. * Объясните *, как это решает проблему. – thecoshman

1

Я разложу операцию prepareStream.str().c_str();, чтобы точно показать, что происходит.

Давайте напишем вместо:

const char* getSystemRunCString(){ 
    const string s = prepareStream.str(); 
    const char * c = s.c_str(); 
    printf("%s - %p\n", c, c); 
    return c; 
} 

он отлично работает и показывает готовит командную строку

Но по возвращении на метод, если я использую

const char *c = systemRunner->getSystemRunCString(); 
printf("%s - %p\n", c, c); 

по адресу указателя в том же, но сама строка исчезла.

Explaination:

Под капотом prepareStream.str().c_str(); создает локальную строку и получает const char * на его содержание. Но поскольку строка нигде не сохраняется, она выходит за пределы области действия, и ее содержимое исчезает.

Так что ваша проблема не в system уровне, но связано с тем, что для stringstream ss, ss.str().c_str() неверно, потому что вы получаете указатель на строку, которая выходит из области видимости в конце инструкции.

Это работает, если вы пишете string s = prepareStream.str().c_str(); потому что внутренняя строка идет только из области видимости в конце инструкции, и во время обучения значения копируются в новую строку.

Смежные вопросы