C ++ Изменение логических переменных - PullRequest
3 голосов
/ 11 апреля 2011

У меня есть класс C ++; этот класс выглядит следующим образом:

Сначала заголовок:

class PageTableEntry {
public:

    PageTableEntry(bool modified = true);
    virtual ~PageTableEntry();

    bool modified();
    void setModified(bool modified);

private:
    PageTableEntry(PageTableEntry &existing);
    PageTableEntry &operator=(PageTableEntry &rhs);

    bool _modified;
};

И файл .cpp

#include "PageTableEntry.h"

PageTableEntry::PageTableEntry(bool modified) {
    _modified = modified;
}

PageTableEntry::~PageTableEntry() {}

bool PageTableEntry::modified() {
    return _modified;
}
void PageTableEntry::setModified(bool modified) {
    _modified = modified;
}

Я установил точку останова на все 3 строки в файле .cpp, включая _modified, чтобы я мог точно видеть, где они устанавливаются / изменяются / читаются. Последовательность выглядит следующим образом:

  1. Точка останова в конструкторе срабатывает. подтверждено, что _модифицированная переменная имеет значение true
  2. Точка останова в аксессоре срабатывает. _модифицированная переменная ЛОЖЬ!

Это происходит с каждым экземпляром PageTableEntry. Сам класс не меняет переменную - что-то еще. К сожалению, я не знаю что. Класс создается динамически с использованием new и передается (как указатели) различным структурам STL, включая вектор и карту. Мутатор никогда не вызывается из моего собственного кода (я еще не дошел до этого момента), и структуры STL не должны этого делать, и поскольку точка останова никогда не вызывается у мутатора, я могу только предположить, что они не являются .

Ясно, что есть некоторая «ошибка», когда частные переменные могут, при определенных обстоятельствах, быть изменены без прохождения через мутатор класса, вызванный ситуацией «кто знает, что», но я не могу себе представить, что это может быть. Есть мысли?

UPDATE: Значение это на каждом этапе:
Конструктор 1: 0x100100210
Конструктор 2: 0x100100400
Accessor 1: 0x1001003f0
Accessor 2: 0x100100440

UPDATE2:
(код, показывающий, где осуществляется доступ к PageTableEntry)

// In constructor:
    _tableEntries = std::map<unsigned int, PageTableEntry *>();

// To get an entry in the table (body of testAddr() function, address is an unsigned int:
    std::map<unsigned int, PageTableEntry *>::iterator it;
    it = _tableEntries.find(address);
    if (it == _tableEntries.end()) {
        return NULL;
    }
    return (PageTableEntry *)&(*it);

// To create a new entry:
    PageTableEntry *entry = testAddr(address);
    if (!entry) {
        entry = new PageTableEntry(_currentProcessID, 0, true, kStorageTypeDoesNotExist);
        _tableEntries.insert(std::pair<unsigned int, PageTableEntry *>(address, entry));
    }

Это единственные точки, в которых объекты PageTableEntry хранятся и извлекаются из структур STL, чтобы вызвать проблему. Все остальные функции используют функцию testAddr () для извлечения записей.

UNRELATED: Поскольку в C ++ сейчас 65663 вопроса, а сегодня было задано 164 вопроса, это означает, что только сегодня число вопросов с тегами C ++ превысило 16-разрядное целое число без знака. Полезно? Интересно? Да. :)

Ответы [ 5 ]

9 голосов
/ 11 апреля 2011

Либо ваш отладчик не сообщает правильно значение (не неслыханно и даже ожидаемо в оптимизированных сборках), либо у вас повреждена память в других местах вашей программы. Код, который вы показали, более или менее хорош и должен вести себя так, как вы ожидаете.


РЕДАКТИРОВАТЬ, соответствующие вашему UPDATE2:
Проблема в этой строке:

return (PageTableEntry *)&(*it);

Тип *it - это std::pair<unsigned const, PageTableEntry*>&, так что вы фактически реинтерпретируете приведение std::pair<unsigned const, PageTableEntry*>* к PageTableEntry*. Измените эту строку на:

return it->second;

Следите за другими приведениями в вашей кодовой базе. Прежде всего, необходимость приведения - это запах кода, и результатом неправильного выполнения приведения может быть неопределенное поведение, в том числе проявление повреждения памяти, как вы видите здесь. Использование приведений в стиле C ++ вместо приведений в стиле C упрощает поиск мест, где происходят преобразования в вашей кодовой базе, поэтому их можно легко просмотреть (подсказка , подсказка ).

3 голосов
/ 11 апреля 2011

std::map<>::find() возвращает iterator, которое при разыменовании возвращает std::map<>::value_type.value_type в этом случае - std::pair<>.Вы возвращаете адрес этого pair, а не PageTableEntry.Я полагаю, вы хотите следующее:

// To get an entry in the table (body of testAddr() function, address is an unsigned int:
std::map<unsigned int, PageTableEntry *>::iterator it;
it = _tableEntries.find(address);
if (it == _tableEntries.end()) {
    return NULL;
}
return (*it).second;

PS: броски в стиле C являются злом.Компилятор выпустил бы диагностику с приведением C ++.:)

3 голосов
/ 11 апреля 2011

Попробуйте посмотреть значение this в каждой точке останова.

0 голосов
/ 11 апреля 2011

Не могли бы вы добавить еще одно уникальное значение в класс для отслеживания PageTableEntry s?Я знаю, что у меня были проблемы, подобные этой, где реальная проблема заключалась в том, что было несколько записей, которые выглядели одинаково, и точки останова могли переключать PageTableEntry, даже если я этого не осознавал.

0 голосов
/ 11 апреля 2011

Этот конструктор копирования и оператор присваивания будут часто использоваться, если вы используете контейнеры STL.Может быть, если вы покажете нам код для них, мы увидим что-то не так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...