0

我有一个带有parse(int argc, char* argv[])函数的类,我必须使用它来设置对象的所需状态。我正在使用 gui 获取参数stringstream,然后尝试将它们转换为 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

4 回答 4

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]

是 achar*但从i中第一个条目的第 th 元素开始argv。例如,如果第一个 c 字符串argv"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'.
于 2012-06-26T14:19:47.837 回答
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_castconst-nedd 远离由 . 返回的指针c_str()。演员表本身是合法的,如果不是反模式的话。但是,如果您稍后尝试修改存储在该指针处的数据,那就是未定义的行为。

以下是标准必须说的c_str()

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

const charT* c_str() const;

1/ 返回: 指向长度为 size() + 1 的数组的初始元素的指针,其第一个 size() 元素等于由 *this 控制的字符串的相应元素,其最后一个元素是 charT() 指定的空字符.

2/ 要求:程序不得更改存储在数组中的任何值。在任何后续调用指定与 this 相同的对象的类 basic_string 的非常量成员函数之后,程序也不会将返回值视为有效指针值。常量 charT* 数据()常量;

3/ 返回:如果 size() 不为零,则该成员返回指向数组初始元素的指针,该数组的第一个 size() 元素等于由 *this 控制的字符串的相应元素。如果 size() 为零,则该成员返回一个非空指针,该指针是可复制的并且可以添加零。

4/ 要求:程序不得更改存储在字符数组中的任何值。在对指定与 this 相同的对象的 basic_string 的非 const 成员函数的任何后续调用之后,程序也不会将返回值视为有效指针值。allocator_type get_allocator() 常量;

5/ 返回:用于构造字符串的分配器对象的副本。

于 2012-06-26T14:26:11.833 回答
1

您忘记i在循环中初始化变量。并且您试图仅打印出 vector 中的第一项argv

for (int i = 0; i < argc; ++i)
    std::cout << argv[i];
于 2012-06-26T14:31:38.360 回答
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());
于 2012-06-26T15:13:40.373 回答