【问题标题】:C++ Access violation when deferencing pointer to a class member取消引用指向类成员的指针时发生 C++ 访问冲突
【发布时间】:2018-11-28 14:33:13
【问题描述】:

在我的程序中,我试图取消引用指向结构文章的指针,以获取其 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_,我保留了所有这些,因此 word_dict_ 中不应出现空指针;

在此处生成字典。

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 = "";
                }
            }
        }
    }
}

最后但同样重要的是,我想把它打印出来,真正的乐趣从这里开始。

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() 中调用的,巧合的是立即连续调用。 word_dict_ 是类私有变量。

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

【问题讨论】:

  • 0xCCCCCCCC 表示未初始化的堆栈内存。 stackoverflow.com/questions/127386/…
  • 这发生在调试中,表明您正在取消引用一个未初始化的指针。
  • 但是访问冲突对我来说太笼统了 -- 你需要习惯它。 C++ 编程需要调试(和避免)这些问题的知识。但是为什么你会陷入存储任何东西的地址的水平呢?程序的设置不需要低级地址甚至指针。
  • word_dict_[buffer][&amp;ar] = wordStart; 在我看来非常可疑。
  • "我尝试了很多不同的东西,局部变量,将指针回溯到代码中,不同的括号......但是什么都没有。" 你有没有尝试过你的使用调试器编写代码,同时观察所有变量的值?

标签: c++ access-violation dereference


【解决方案1】:
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_ 中的指针将变为无效。

【讨论】:

    【解决方案2】:
    for (Article ar : articles_)
    

    这会复制您的文章,作为局部变量。一旦循环的下一次迭代开始,这个局部变量就会超出范围。

    word_dict_[buffer][&ar] = wordStart;
    

    在这里你存储一个指向局部变量的指针,它只在你的循环内有效。

    如果您可以确保您的文章比您的地图寿命更长,您可以存储指向存储在articles_ 中的文章的指针。请注意,如果articles_ 是std::vector,当您将新文章插入其中时,它可能会被重新分配,因此必须小心地在其中存储指向对象的指针,确保在std::vector 更改时使它们无效.

    如果以上所有内容听起来都像你的那杯茶,那么你很可能想要创建对文章的引用,就像这样

    for (Article& ar : articles_)
    

    如果以上听起来有点复杂,您有两种可能的方法。

    1. 让您的 word_dict_ 映射按值存储 Article 对象,而不是作为指针。这种方法的缺点是您将文章存储两次,这具有逻辑含义(对地图中文章的更改不会反映在 articles_ 向量中,反之亦然)以及内存影响(您使用双记忆)

    2. 创建您的articles_ 矢量存储std::unique_ptr&lt;Article&gt;。这样,您无需手动管理向量内的重新分配。您仍然需要管理文章从articles_ 向量中删除 的情况,并确保将其从word_dict_ 映射中删除。这种方法的缺点是默认情况下它使您的类不可复制(std::unique_ptr 有一个已删除的复制构造函数),这对您来说可能是也可能不是问题。如果您需要复制它们,则需要手动提供复制ctor和复制赋值运算符,以及手动实现或= default其他3个特殊成员函数(参见Rule of 5)

    【讨论】:

      猜你喜欢
      • 2018-04-17
      • 2014-05-09
      • 2018-11-02
      • 1970-01-01
      • 1970-01-01
      • 2014-03-16
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多