【问题标题】:C++ std::vector entries are NULL in function, but size remains above zeroC++ std::vector 条目在函数中为 NULL,但大小保持在零以上
【发布时间】: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


【解决方案1】:

首先不清楚为什么需要通过指针而不是值来存储test 对象。如果您确实需要它,请使用智能指针。

至于你的问题,你为什么要返回指向迭代器的指针?这是您的问题的根本原因 - 使 &amp;i 合法返回您将其设为 static,但 static 局部变量仅初始化一次并且不更改值 btw 调用 - 所以在第一次调用后它指向一个元素在向量中,但之后您添加了元素并使所有迭代器无效,包括静态i 导致分段错误。所以修复很简单 - 按值返回迭代器并使 i 非静态但常规,它很轻,这样做完全没问题。

_ 开头的PS 标识符在全局上下文中是非法的,详细信息可以在这里找到What are the rules about using an underscore in a C++ identifier?

所以你的函数实际上应该是这样的:

static std::vector<test *>::iterator  is_in_vector( std::vector<test *> &vect, const std::string &find) 
{
      return std::find_if( vect.begin(), vect.end(), [find]( test *p ) {
          return p->get_name() == find;
      } );
}

假设向量永远不应该持有nullptr,如果是这种情况还是为了安全起见将条件更改为:

          return p && p->get_name() == find;

【讨论】:

  • 有了你的意见,我已经解决了,但没有std::find_if。我会看看。感谢您的额外努力:-)
猜你喜欢
  • 2020-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多