【发布时间】:2019-10-21 19:35:25
【问题描述】:
我用 C/C++ 编写代码已经有一段时间了,我已经找到了解决问题的替代方案,但我想知道为什么原始代码不起作用。
我有一个测试类,它基本上只存储一个字符串。
class test {
private:
std::string name;
public:
test(std::string name) : name(name) {};
std::string get_name() { return name; }
};
在main 中,我有一个向量,我在某一时刻用test 对象填充。下面的代码模拟了向量vect的不规则使用。
int main(void) {
std::vector<test *> vect;
std::vector<test *>::iterator i;
//* Comment this for a working example
std::cout << "Searching empty vector" << std::endl;
i = *(_is_in_vector(vect, std::string("test 3")));
if (i == vect.end()) {
std::cout << "Nothing found" << std::endl;
} // */
vect.push_back(new test("test 1"));
vect.push_back(new test("test 2"));
vect.push_back(new test("test 3"));
std::cout << "All:" << std::endl;
i = *(_is_in_vector(vect, std::string("test 3")));
if (i != vect.end()) {
std::cout << "Erase " << (*i)->get_name() << std::endl;
vect.erase(i);
delete *i;
}
i = *(_is_in_vector(vect, std::string("test 3")));
if (i == vect.end()) {
std::cout << "Nothing found" << std::endl;
}
std::cout << "Left:" << std::endl;
for (i = vect.begin(); i!=vect.end(); ++i) {
std::cout << (*i)->get_name() << std::endl;
delete *i;
}
vect.clear();
return 0;
}
因为在向量中搜索 test 对象会发生多次,所以我创建了函数 _is_in_vector 来搜索 test 对象并将迭代器返回给它。
static std::vector<test *>::iterator * _is_in_vector(std::vector<test *> &vect, std::string find) {
std::string identity = find;
static std::vector<test *>::iterator i = vect.begin();
std::cout << "Vect size: " << vect.size() << std::endl;
for (i; i != vect.end(); ++i) {
std::string tmp = (*i)->get_name(); /* Segmentation fault after filling vector*/
if (0 == identity.compare(tmp)) break;
}
return &i;
}
问题是,当我注释掉main 中的Searching empty vector 部分时,上面的代码有效。一旦向量被test 对象填充,我第二次调用_is_in_vector。此函数中的向量确实有三个条目,但(*i) 都指向NULL。
输出:
Searching empty vector
Vect size: 0
Nothing found
All:
Vect size: 3
Segmentation fault
预期输出:
Searching empty vector
Vect size: 0
Nothing found
All:
Vect size: 3
Erase test 3
Vect size: 2
Nothing found
Left:
test 1
test 2
【问题讨论】:
-
函数名
_is_in_vector在 C++ 中是非法的。这很可能与您的问题无关,但您应该注意。 -
_is_in_vector()返回一个指向局部变量的指针,该变量在函数返回时不再存在。这会导致调用者收到一个悬空引用,并且该引用的后续使用会产生未定义的行为。函数的名称也保留在全局命名空间中,因此(本身)也会导致未定义的行为。 -
哦,在那种情况下,它只是令人震惊的风格,而不是 UB。在将
i传递给erase之后取消引用它,但是,is 仍然是 UB。 -
vect.erase(i);然后delete *i;使迭代器 i 无效。您可能想先删除,然后再擦除。 -
注意。如果您更改
static ... i的声明,因此您在每次调用时都设置它,而不是只初始化一次 - 它仍然会令人震惊,但实际上不会在那里被破坏。显然,取消引用无效迭代器的问题也需要修复。
标签: c++ vector iterator segmentation-fault