Нарушение доступа C ++ при указании ссылки на член класса - PullRequest
0 голосов
/ 28 ноября 2018

В моей программе я пытаюсь разыменовать указатель на структуру Article, чтобы получить ее идентификатор, но я получаю «Место чтения нарушения доступа 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_ является закрытой переменной класса.

Если есть необходимость в каких-либо других частях кода, просто дайте мне знать, хотя ни один из других не должен создавать никаких проблем в этом случае.

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018
for (Article ar : articles_)

Выполняет копирование вашей статьи в качестве локальной переменной.Эта локальная переменная выходит из области видимости, как только оборачивается следующая итерация цикла.

word_dict_[buffer][&ar] = wordStart;

Здесь вы храните указатель на локальную переменную, которая действительна только внутри вашего цикла.

Если вы можете быть уверены, что ваши статьи переживут вашу карту, вы можете сохранить указатель на статьи, хранящиеся в articles_.Обратите внимание, что если articles_ является std::vector, оно может быть перераспределено, когда вы вставляете в него новые статьи, поэтому хранение указателей на объект внутри него должно быть сделано аккуратно, при этом убедитесь, что они недействительны при изменении std::vector,

Если все вышеперечисленное звучит как ваша чашка чая, вы, скорее всего, захотите создать ссылку на статью, например так:

for (Article& ar : articles_)

Если вышеприведенное звучит слишком сложно,у вас есть 2 возможных подхода.

  1. Создайте word_dict_ карту для хранения Article объектов по значению, а не как указатели.Недостатком этого подхода является то, что вы храните свои статьи дважды, что имеет логические последствия (изменения в статье внутри вашей карты не будут отражаться в векторе articles_ и наоборот), а также последствия для памяти (вы используете двойноепамять)

  2. Создайте articles_ векторный магазин std::unique_ptr<Article>.Таким образом, вам не нужно вручную управлять перераспределениями внутри вашего вектора.Вам все равно нужно будет управлять случаем, когда Статья удалена из вектора articles_, и обязательно удалить ее с карты word_dict_.Недостатком этого подхода является то, что он по умолчанию делает ваш класс не копируемым (std::unique_ptr имеет конструктор удаленных копий), что может быть или не быть проблемой для вас.Если вам нужно, чтобы они были скопированы, вам нужно будет вручную указать ctor и оператор копирования, а также реализовать вручную или = default другие 3 специальные функции-члены (см. Правило 5 )

0 голосов
/ 28 ноября 2018
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_ становятсянедействительный.

...