我有一个具有parse(int argc, char* argv[])
函数的类,我必须使用它来设置对象的所需状态。我使用stringstream
从gui中获取参数,然后我尝试将它们转换为char **以将它们传递给函数。这就是我所拥有的:
std::stringstream sstream;
sstream << "-clip" << " " << min_x_entry.get_text()
<< " " << max_x_entry.get_text(); // etc.
std::cout << sstream.str(); // All looks good here
std::vector<std::string> args;
std::vector<char*> argv;
std::string arg;
while (sstream >> arg)
{
args.push_back(arg);
argv.push_back(const_cast<char*>(args.back().c_str()));
}
argv.push_back(0);
int argc = args.size();
for (int i = 0; i < argc; ++i)
std::cout << &argv[0][i]; // This outputs garbage
my_object.parse(argc, &argv[0]) // And this fails
我错过了什么?有没有更好的方法来实现这一目标?
答案 0 :(得分:5)
问题是重新分配args
向量,因为push_back()
会增加向量的大小,如果需要:
如果new size()不大于capacity(),则不会使迭代器或引用无效。 否则所有迭代器和引用都将失效。
argv
向量存储指向args
中元素内部的指针,因此这些指针将无效。
解决方案是首先创建args
向量,然后创建argv
向量:
while (sstream >> arg) args.push_back(arg);
for (auto i = args.begin(); i != args.end(); i++)
{
argv.push_back(const_cast<char*>(i->c_str()));
}
argv.push_back(0);
打印出for
字符串的argv
循环不正确。这样:
&argv[0][i]
是char*
,但是从i
中第一个条目的argv
元素开始。例如,如果argv
中的第一个c字符串为"string"
:
&argv[0][1] is "tring"
&argv[0][2] is "ring"
更改为:
for (int i = 0; i < argc; i++)
std::cout << argv[i] << std::endl; // Added 'endl' to flush 'cout'.
答案 1 :(得分:3)
std::vector<std::string> args;
std::vector<char*> argv;
/* ... */
argv.push_back(const_cast<char*>(args.back().c_str()));
这里有很多问题。
c_str()
返回的指针不能保证在后续调用同一const
的非string
成员函数后有效。从c_str()
返回的指针通常不应存储并在以后使用,尤其是如果您不确定其他代码是否会调用const
的非string
成员。const_cast
const
远离c_str()
返回的指针。演员本身是合法的,如果不是反模式。但是,如果您稍后尝试修改存储在该指针的数据,那就是未定义的行为。以下是标准对c_str()
所说的内容:
const charT* c_str() const;
1 /返回:指向长度数组的初始元素的指针 size()+ 1,其第一个size()元素等于对应的 字符串的元素由* this控制,其最后一个元素是a charT()指定的空字符。
2 /要求:程序不得更改存储的任何值 数组。程序也不应将返回值视为有效值 任何后续调用非const成员函数后的指针值 basic_string类,指定与此相同的对象。 const charT * data()const;
3 /返回:如果size()非零,则成员返回指向的值 数组的初始元素,其第一个size()元素等于 由* this控制的字符串的相应元素。如果size()是 零,该成员返回一个可复制的非空指针 添加零。
4 /要求:程序不得改变存储的任何值 字符数组。程序也不应将返回值视为 任何后续调用非const成员后的有效指针值 basic_string的函数,指定与此相同的对象。 allocator_type get_allocator()const;
5 /返回:用于构造的Allocator对象的副本 字符串。
答案 2 :(得分:1)
您忘记在循环中初始化变量i
。而您正在尝试仅打印向量argv
中的第一项。
for (int i = 0; i < argc; ++i)
std::cout << argv[i];
答案 3 :(得分:0)
你可以摆脱const_cast
而不用担心parse()
方法可能会通过这样的方式修改参数:
std::vector<std::vector<char>> args;
std::for_each(std::istream_iterator<std::string>(sstream),
std::istream_iterator<std::string>(),
[&args](const std::string& str)
{
std::vector<char> temp(str.begin(), str.end());
temp.push_back('\0');
args.push_back(temp);
});
std::vector<char*> argv(args.size());
for (auto& v : args) argv.push_back(v.data());
my_object.parse(argv.size(), argv.data());