延迟指向类成员的指针时发生C ++访问冲突

时间:2018-11-28 14:33:13

标签: c++ access-violation dereference

在我的程序中,我试图取消对结构文章的指针的引用,以获取其ID,但我得到的是“访问冲突读取位置0xCCCCCCCC”。我尝试了许多不同的事情,局部变量,将指针回溯到代码中,使用不同的括号……尽管没有。我没有选择余地,但是无论我怎么努力,我都看不到问题。

这个问题可能有一个答案,但是访问冲突对我来说太笼统了,无法找到我要寻找的答案(大多数问题都围绕数组,这不是我的情况)

在这里,我定义了一个简单的结构来保存我的数据。

struct Article {
public:
    std::string id;
    std::string title;
    std::string text;
    Article(std::string article_id, std::string article_title, std::string article_text) : id(article_id), title(article_title), text(article_text) {};
    void toString();
};

接下来,我使用字典将所有单词映射到它们出现的文章。代码本身并没有完成,但是单词映射应该包括所有必要的指针。

std::map<std::string, std::map<Article*, unsigned>> word_dict_;

在保留所有vector<Article> articles_的同时,我还要保留另一个void fulltext::generateDict() { for (Article ar : articles_) { unsigned wordStart; bool isBuilding = false; string buffer = ""; for (unsigned int it = 0; it <= ar.text.size(); ++it) { char c; if (it < ar.text.size()) c = ar.text.at(it); else c = '\0'; if (isalpha(c)) { // start or middle of word if (!isBuilding) { isBuilding = true; wordStart = it; } buffer += c; } else { isBuilding = false; if (buffer != "") { stringToLower(buffer); // rewrites buffer to low case // Here I tried creating &ar just for the laughs and it works just fine. word_dict_[buffer][&ar] = wordStart; buffer = ""; } } } } } ,因此word_dict_中不应出现空指针;

在这里生成字典。

void fulltext::printWordDict() {

    cout << "Printing generated word dictionary: " << endl;

    for (auto wordPair : word_dict_) {
        cout << " \" " << wordPair.first << " \" " << endl;
        cout << "There are " << wordPair.second.size() << " inputs." << endl;
        for (pair<Article*, unsigned int> articlePair : wordPair.second) {
            cout << (articlePair.first)->id << endl; // Here the access violation occurs
            // Nothing seemingly works
            // cout << articlePair.first->id; ... Access violation
            // cout << (*articlePair.first).id; ... Access violation
            // auto ar = articlePair.first; cout << ar->id; ... access violation
            // auto ar = articlePair.first; cout << (*ar).id; ... access again
        }
        cout << endl;
    }
    cout << "Done." << endl;
}

最后但并非最不重要的一点,我想将其打印出来,然后真正的乐趣就开始了。

fulltext::proccess()

从主函数cordova android build --stagging 内部立即连续调用这些函数。 word_dict_是类私有变量。

如果需要代码的其他任何部分,请告诉我,尽管在这种情况下,其他任何问题都不会出现。

2 个答案:

答案 0 :(得分:4)

for (Article ar : articles_) {
     ...
    word_dict_[buffer][&ar] = wordStart;
    ...
}

这里,您在字典中存储了指向ar的指针,但是ar在其作用域的末尾被破坏-当for循环结束时。因此,现在您在地图中存储了一个悬空指针,无法取消引用。

Article对象存储在地图中而不是Article*,否则,只要您在地图中有指向该对象的指针,请确保Article对象存在。

如果对象保存在articles_容器中,则可能不需要在for循环中复制它,而是执行以下操作:

for (Article& ar : articles_) {
   .. 
   word_dict_[buffer][&ar] = wordStart;

现在,您将获得一个指向Article中的article_对象的指针。

尽管稍后会知道对article_的处理方式-如果对其执行移动对象的操作(根据容器类型的不同,可能会发生多种原因),则word_dict_中的指针变得无效。

答案 1 :(得分:4)

for (Article ar : articles_)

这会执行您的文章的副本,作为局部变量。一旦循环的下一次迭代出现,此局部变量就会超出范围。

word_dict_[buffer][&ar] = wordStart;

这里存储了指向局部变量的指针,该指针仅在循环内部有效。

如果可以确保您的文章将在地图上过期,则可以存储指向articles_中存储的文章的指针。请注意,如果articles_std::vector,则在您向其中插入新文章时可能会对其进行重新分配,因此必须小心地将指向对象的指针存储在其中,并确保在std::vector发生了变化。

如果以上所有听起来都像您喝杯茶,那么您很可能想创建对本文的引用,就像这样

for (Article& ar : articles_)

如果上述操作听起来有点复杂,您可以采用两种方法。

  1. 使您的word_dict_映射存储Article对象通过Value代替指针。这种方法的缺点是您将文章存储两次,这具有逻辑上的含义(对地图内部文章的更改不会反映在articles_向量中,反之亦然)以及内存方面的影响(您使用内存翻倍)

  2. 使您的articles_向量存储区std::unique_ptr<Article>。这样,您将无需手动管理向量内部的重新分配。您仍然需要管理从articles_向量中删除文章的情况,并确保将其从word_dict_地图中删除。这种方法的缺点是,默认情况下它会使您的类无法复制(std::unique_ptr的副本构造函数已删除),这可能对您或不是您的问题。如果需要复制它们,则需要手动提供复制控制器和复制分配运算符,以及手动实现或= default或其他3个特殊成员函数(请参见Rule of 5