在向量上调用 clear() 并不会真正删除 data() 中的数据?

Calling clear() on a vector does not actually delete data in data()?

总结:

似乎仅在矢量上调用 clear() 不足以清除它。

vector_full_of_stuff.clear();

我不得不调用 clear() 然后 shrink_to_fit() 来完全删除其中的所有数据。

vector_full_of_stuff.clear();
// AND THEN  
vector_full_of_stuff.shrink_to_fit();

什么给了?这成为一个问题,因为当我在向量上调用 data() 时,它会包含我认为应该在我早些时候在代码中调用 clear() 时清除的内容。

其他详细信息

我正在做一项计算机网络作业,我必须将 PASV 命令结果解析为 IP 和端口号。在解析以逗号分隔的虚构 PASV 命令结果时,我注意到如果我解析一个三位数后跟一个两位数,我会在调用 data() 时从上一个解析中得到第三个数字,即使我不应该(?)因为我在它之前调用了clear()

ex.
PASV Command Result = 209,202,252,54,19,15
The "2" from "252" carries over into "19" when parsing.

代码:

// this one actually deletes data
void splitString(string str, char delimiter, vector<string> * out) {
    vector<char> word_buffer;
    for (int i = 0; i < str.length(); ++i) {
        if (str[i] == delimiter) {
            out->push_back(word_buffer.data());
            word_buffer.clear();
            word_buffer.shrink_to_fit();
        } else {
            word_buffer.push_back(str[i]);
        }
    }
    out->push_back(word_buffer.data());
    word_buffer.clear();
}
// 

// this one doesn't
// the only thing that's different about this one 
// is that its missing shrink_to_fit()
void splitString(string str, char delimiter, vector<string> * out) {
    vector<char> word_buffer;
    for (int i = 0; i < str.length(); ++i) {
        if (str[i] == delimiter) {
            out->push_back(word_buffer.data());
            word_buffer.clear();
            // word_buffer.shrink_to_fit(); // need this to delete data
        } else {
            word_buffer.push_back(str[i]);
        }
    }
    out->push_back(word_buffer.data());
    word_buffer.clear();
}
//

// main driver code
int main() {
    vector<string> user_input_tokens;
    string port = "209,202,252,54,19,15";
    splitString(port, ',', &user_input_tokens);
    for (string str : user_input_tokens) {
        cout << str << ".";
    }
}
//

预期输出:

209.202.252.54.19.15.

实际输出:

209.202.252.542.192.152.

矢量的 data() 方法 returns 指向矢量在内存中分配的数组的原始指针。 clear() 在需要时销毁该数组的 contents 并将向量的 size() 设置为 0,但不会重新分配数组本身,因此不会更改向量的capacity()。调用向量的 shrink_to_fit() 方法会重新分配数组,以便它的 capacity() 匹配它的 size(),如果可能(shrink_to_fit() 仅供参考,而不是 保证 实际做任何事情)。

此外,当从 char* 指针本身构造 std::string 时,char 数据需要是 null-terminated,但您的数据不是。在使用 data():

之前,您需要将空终止符推入向量中
void splitString(const string &str, char delimiter, vector<string> * out) {
    vector<char> word_buffer;
    for (int i = 0; i < str.length(); ++i) {
        if (str[i] == delimiter) {
            word_buffer.push_back('[=10=]');
            out->push_back(word_buffer.data());
            word_buffer.clear();
        } else {
            word_buffer.push_back(str[i]);
        }
    }
    if (!word_buffer.empty()) {
        word_buffer.push_back('[=10=]')
        out->push_back(word_buffer.data());
    }
}

否则,您可以在构造字符串时简单地考虑向量的 size(),不需要空终止符:

void splitString(const string &str, char delimiter, vector<string> * out) {
    vector<char> word_buffer;
    for (int i = 0; i < str.length(); ++i) {
        if (str[i] == delimiter) {
            out->push_back(string(word_buffer.data(), word_buffer.size()));
            // alternatively:
            // out->emplace_back(word_buffer.data(), word_buffer.size());
            word_buffer.clear();
        }
        else {
            word_buffer.push_back(str[i]);
        }
    }
    if (!word_buffer.empty()) {
        out->push_back(string(word_buffer.data(), word_buffer.size()));
        // alternatively:
        // out->emplace_back(word_buffer.data(), word_buffer.size());
    }
}

也就是说,还有其他方法可以实现 splitString() 函数而根本不需要 word_buffer 向量,例如:

void splitString(const string &str, char delimiter, vector<string> * out) {
    string::size_type start = 0, pos = str.find(delimiter);
    while (pos != string::npos) {
        out->push_back(str.substr(start, pos-start));
        start = pos + 1;
        pos = str.find(delimiter, start);
    }
    if (start < str.size()) {
        if (start > 0) {
            out->push_back(str.substr(start));
        } else {
            out->push_back(str);
        }
    }
}

Live Demo

void splitString(const string &str, char delimiter, vector<string> * out) {
    istringstream iss(str);
    string word;
    while (getline(iss, word, delimiter))
        out->push_back(std::move(word));
}

Live Demo

但是,即使您想手动缓冲单词,std::string 也比 std::vector<char> 更有意义,尤其是因为您正在输出 std::string 值:

void splitString(const string &str, char delimiter, vector<string> * out) {
    string word_buffer;
    for (string::size_type i = 0; i < str.length(); ++i) {
        if (str[i] == delimiter) {
            out->push_back(std::move(word_buffer));
            word_buffer.clear();
        } else {
            word_buffer.push_back(str[i]);
        }
    }
    if (!word_buffer.empty()) {
        out->push_back(std::move(word_buffer));
    }
}

Live Demo