这与“为什么简单system(variable)
不起作用”之类的内容不重复。
该解决方案只是将字符串存储到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() )
但它失败了,不过。编译很好,但是当像这样调用system()时 - 系统说它无法找到指定的路径。
但是,当我将其恢复并在直接系统调用中使用c_str()
时,例如像这样:
string tmp = (string)systemRunner->getSystemRunCString();
system( tmp.c_str() );
这很好用。
如果我创建一个与c_str()
返回相同内容的方法,可以预期
const char*
,我会得到相同的结果,但我没有得到它......
我甚至试图将两个输入都放在system()
但文件中 - 相同的结果,因此它存储相同的信息......
我错过了什么吗?这甚至可能吗?
PS:我说的是在Windows 7控制台应用程序中使用system()
...
编辑:那么@ravi对于导致这个特定示例失败的原因是正确的 - 但是主题的答案在标题中是什么 - 是否可以调用系统(变量)没有直接调用c_str()吗? :)
答案 0 :(得分:5)
return this->prepareStream.str().c_str();
将返回const char *。该指针将是指向字符串类使用的内部字符指针的指针。通过这个操作,你可以访问字符串的内部数据,但是因为它是const指针,你将无法修改它的内容。
这里发生的事情是在执行此函数后,字符串(您仍然保留其内部数据)超出范围。所以,你只是在处理其字符串超出范围的句柄。
你永远不应该依赖于此。
答案 1 :(得分: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()
方法。
答案 2 :(得分: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
这也适用于Rudolfs Bundulis的回答。
答案 3 :(得分: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);
指针地址相同,但字符串本身已经消失。
解释:
在幕后,prepareStream.str().c_str();
创建一个本地字符串,并在其内容上获得const char *
。但是由于字符串没有保存在任何地方,因此它超出范围并且其内容消失。
所以你的问题不在system
级别,但与stringstream ss
,ss.str().c_str()
不正确的事实有关,因为你得到一个指向一个字符串的指针指示结束时的范围。
如果您编写string s = prepareStream.str().c_str();
,它会起作用,因为内部字符串仅在指令末尾超出范围,而在指令期间将值复制到新字符串。< / p>