C ++:从stringstream到char **

时间:2012-06-26 14:14:27

标签: c++ string stdvector stringstream

我有一个具有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

我错过了什么?有没有更好的方法来实现这一目标?

4 个答案:

答案 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()));

这里有很多问题。

  1. c_str()返回的指针不能保证在后续调用同一const的非string成员函数后有效。从c_str()返回的指针通常不应存储并在以后使用,尤其是如果您不确定其他代码是否会调用const的非string成员。
  2. const_cast const远离c_str()返回的指针。演员本身是合法的,如果不是反模式。但是,如果您稍后尝试修改存储在该指针的数据,那就是未定义的行为。
  3. 以下是标准对c_str()所说的内容:

    21.3.6 basic_string字符串操作[lib.string.ops]

    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());