1

In my program, I'm trying to dereference a pointer to a struct Article, to get its id, but I'm getting "Access violation reading location 0xCCCCCCCC". I've tried many different things, local variables, backtracking the pointers back into the code, different parentheses... nothing though. I'm out of options and I can't see the problem however hard I try.

There might be an answer to this question, but access violation is much too general for me to be able to find the answer I'm looking for (also most of the questions go around arrays, which aren't my case).

Here I define a simple struct to keep my data.

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

Next, I use a dictionary that maps all words to the articles where they appear. The code is not done itself, but maps of words should include all the necessary pointers.

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

I also keep another vector<Article> articles_ wher I keep all of them, so no null pointers should appear in the word_dict_;

Here the dictionary gets generated.

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

Last but not least, I want to have it printed out and here the real fun starts.

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

These functions are called from within a main function fulltext::proccess() coincidentally in immediate succession. The word_dict_ is class private variable.

If there's need for any other parts of the code, just let me know, although none of the others should make any issues in this case.

Samuel Novelinka
  • 328
  • 3
  • 10
  • 2
    0xCCCCCCCC means uninitialized stack memory. https://stackoverflow.com/questions/127386/in-visual-studio-c-what-are-the-memory-allocation-representations – drescherjm Nov 28 '18 at 14:34
  • This happens in debug and indicates that you are dereferencing a pointer that was not initialized. – Matthieu Brucher Nov 28 '18 at 14:34
  • *but access violation is much too general for me* -- You need to get used to it. C++ programming requires knowledge of debugging (and avoiding) these issues. But why are you sinking to the level of storing addresses of anything? The setup of your program doesn't require low-level addresses or even pointers. – PaulMcKenzie Nov 28 '18 at 14:35
  • `word_dict_[buffer][&ar] = wordStart;` looks very suspicious to me. – drescherjm Nov 28 '18 at 14:36
  • 1
    "_I've tried many different things, local variables, backtracking the pointers back into the code, different parentheses... nothing though._" Did you try stepping through your code with a debugger, while observing the values, of all variables? – Algirdas Preidžius Nov 28 '18 at 14:37

2 Answers2

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

Here you are storing a pointer to ar in your dictionary, however ar is destroyed at the end of its scope - when your for loop ends. So now you are storing a dangling pointer in your map, which you cannot de-reference.

Store Article objects in your map instead of Article* , or otherwise ensure the Article object lives somewhere as long as you have a pointer to it in your map.

If you have the objects live in your articles_ container, you might not need to copy it in your for loop, and instead do:

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

Now you'll get a pointer to your Article object that resides within article_.

Though be aware what you do with article_ later on - if you perform operations on it that moves objects around (which can happen for many reasons depending on the container type), your pointers within word_dict_ becomes invalid.

nos
  • 223,662
  • 58
  • 417
  • 506
4
for (Article ar : articles_)

This performs a copy of your article, as a local variable. This local variable goes out of scope as soon as the next iteration of the loop rolls around.

word_dict_[buffer][&ar] = wordStart;

Here you store a pointer to the local variable, that is valid only inside your loop.

If you can ensure that your articles will outlive your map, you can store a pointer to the articles stored in articles_. Take note, that if articles_ is a std::vector, it might get reallocated when you insert new articles into it, so storing pointers to object inside it has to be done carefully, making sure to invalidate them when the std::vector changes.

If all of the above sounds like your cup of tea, You most probably want to create a reference to the article, like so

for (Article& ar : articles_)

If the above sounds a bit too complicated, you have 2 possible approaches.

  1. Make your word_dict_ map store Article objects by Value, instead of as pointers. Downside of this approach is that you store your articles twice, which has logical implications (changes to the article inside your map won't be reflected in the articles_ vector and vice-versa) as well as memory implications (you use double the memory)

  2. Make your articles_ vector store std::unique_ptr<Article>. This way, you won't need to manually manage the reallocations inside your vector. You will still need to manage the case where an Article is removed from the articles_ vector, and make sure to remove it from the word_dict_ map. The downside of this approach is that it makes your class uncopiable by default (std::unique_ptr has a deleted copy constructor), which might or might not be a problem for you. If you need them to be copied, you would need to manually provide a copy ctor and copy assignment operator, as well manually implement or = default the other 3 special member functions (see Rule of 5)

divinas
  • 1,787
  • 12
  • 12