首页 > 解决方案 > 在向量上调用 clear() 实际上不会删除 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()在它之前调用过.

前任。
PASV 命令结果 = 209,202,252,54,19,15
“252”中的“2”在解析时会延续到“19”。

代码

// 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.

标签: c++vectorstleraseshrink

解决方案


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

std::string此外,当自己从指针构造 a 时char*,char 数据需要以空值结尾,但您的数据不是。在使用之前,您需要将空终止符推入向量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('\0');
            out->push_back(word_buffer.data());
            word_buffer.clear();
        } else {
            word_buffer.push_back(str[i]);
        }
    }
    if (!word_buffer.empty()) {
        word_buffer.push_back('\0')
        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);
        }
    }
}

现场演示

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

现场演示

但是,即使您想手动缓冲单词, astd::string也会比 a 更有意义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));
    }
}

现场演示


推荐阅读