【问题标题】:Can't add item to const char* vector? C++无法将项目添加到 const char* 向量? C++
【发布时间】:2018-08-11 06:11:24
【问题描述】:

我有一个问题,我需要一个 const char* 向量,但由于某种原因,每当我尝试添加一些东西时,什么都没有发生。这是有问题的代码示例。

std::vector<const char*> getArgsFromFile(char* arg) {
    std::ifstream argsFile(arg);
    std::vector<const char*> args;
    while (!argsFile.eof()) {
        std::string temp;
        argsFile >> temp;
        args.push_back(temp.c_str());
    }
    args.pop_back();
    return args;
}

奇怪的是,如果我做出这个改变

std::vector<const char*> getArgsFromFile(char* arg) {
    std::ifstream argsFile(arg);
    std::vector<const char*> args;
    while (!argsFile.eof()) {
        std::string temp;
        argsFile >> temp;
        const char* x = "x";
        args.push_back(x);
    }
    args.pop_back();
    return args;
}

它会将“x”添加到向量中,但我无法将 temp 的值添加到向量中。有什么想法吗?帮助将不胜感激。谢谢!

【问题讨论】:

  • temp 超出范围时,c_str 的返回值超出范围。 x 正在工作,因为它卡在二进制文件的只读存储中,因此它永远不会消失。
  • 你不需要一个 char * 的向量,你需要一个 std::string 的向量。此外,您对 eof() 的使用是错误的 - 请参阅 stackoverflow.com/questions/5605125/…
  • 我需要一个 char* 的向量,它是我作业的一部分,我们不能使用字符串向量
  • 然后您需要调用new char[size],复制字符串,将字符数组添加到向量中,并确保在程序结束时分配的所有内容上调用delete []
  • @MillieSmith: "并确保在分配的所有内容上调用 delete []" - 如果您必须使用 new char[] 而不是 std::string,那么您应该使用std::vector&lt;std::unique_ptr&lt;char[]&gt;&gt; 而不是 std::vector&lt;char*&gt;,并在 vector 被清除/销毁时让 std::unique_ptr 为您处理释放。

标签: c++ string vector char c-strings


【解决方案1】:

const char*不是字符串,而只是指向某些内存的指针,通常包含一些字符。现在 std::string 在后台要么拥有一小块内存区域(如 char buff[32]),要么对于较大的字符串,保留指向在堆上分配的内存的指针。无论哪种情况,都可以通过string::c_str() 获得指向保存数据的实际内存的指针。但是当string 超出范围时,该指针不再指向受保护的数据并变得悬空。

这就是 C++ 引入避免直接暴露和使用原始指针的方法的原因。好的 C++ 代码避免像瘟疫这样的原始指针。你的作业是针对糟糕/糟糕的 C++ 代码(希望只是为了了解这些原始指针带来的问题)。

因此,为了使vector 中的指针持久指向某些字符(而不是悬空),它们必须指向持久内存。实现这一目标的唯一保证方法是动态分配内存

while (!argsFile.eof()) {
    std::string temp;
    argsFile >> temp;
    char* buff = new char[temp.size()+1];          // allocate memory
    std::strncpy(buff,temp.c_str(),temp.size()+1); // copy data to memory
    args.push_back(buff);                          // store pointer in vector
}

但是这样分配的内存会被泄露,除非你像下面这样取消分配

while(!args.empty()) {
    delete[] args.back();
    args.pop_back();
}

请注意,这是非常糟糕的 C++ 代码并且不是异常安全的(如果在分配和解除分配之间发生异常,则分配的内存会泄漏)。在 C++ 中,可以改用 std::vector&lt;std::string&gt;std::vector&lt;std::unique_ptr&lt;const char[]&gt;(如果您不能使用 std::string),两者都是异常安全的。

【讨论】:

  • std::string管理的数据不一定存放在任何堆中。
  • stdd::string 并不总是持有指针 - small string optimization
【解决方案2】:

使用基于标准库的实现

C++ coding guidelines 的指南 SL.1 说:“尽可能使用标准库”(并且相关)。为什么要这么努力?人们已经为您完成了大部分工作...

因此,使用您的函数声明,您可以:

std::vector<std::string> getArgsFromFile(char* arg) {
    using namespace std;
    ifstream argsFile(arg);
    vector<string> args;
    copy(istream_iterator<string>(argsFile),
          istream_iterator<string>(),
          back_inserter(args));
    return args;
}

鲍勃是你的叔叔。

不过,@Walter 的 answer 非常适合阅读,这样您就会意识到将 char * 用于字符串有什么问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    • 2022-01-10
    • 2022-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多