почему вектор в классе автоматически становится NULL - PullRequest
0 голосов
/ 08 июня 2019

Я создаю простую модель кэша для имитации определенных приложений.

Но проблема возникает в lru из кода ниже.(Я не копировал несвязанные коды)

main.cpp

int main(void) {
  Cache* L1Cache = new Cache(64, 64, 8);
  Cache* L2Cache = new Cache(256, 64, 4);
  Cache* L3Cache = new Cache(2048, 64, 16); // This object causes problem
  Cache* L4Cache = new Cache(2048, 64, 8);

  L1Cache->initCache();
  L2Cache->initCache();
  L3Cache->initCache();
  L4Cache->initCache();
  return 0;
}

Cache.h

typedef struct CacheLine {
  std::vector<uint64_t> data;
}CacheLine;

typedef struct CacheSet {
  std::vector<bool> valid;
  std::vector<uint64_t> tag;
  std::vector<CacheLine> directory;
}CacheSet;

typedef struct LRU {
  std::vector<std::vector<bool>> lruMatrix;
}LRU;


class Cache {
public:
  Cache(uint32_t cacheSizeInKB, uint32_t lineSizeInByte, uint32_t numOfDirs) {
    // set cache size
    this->cacheSizeInKB = cacheSizeInKB;
    this->lineSizeInByte = lineSizeInByte;
    this->numOfDirs = numOfDirs;
    this->numOfSets = (cacheSizeInKB * 1024) / (lineSizeInByte * numOfDirs);

    // set memory address offset
    this->blockOffsetFrom = log2(lineSizeInByte) - 1;
    this->blockOffsetTo = 0;
    this->indexOffsetFrom = this->blockOffsetFrom + ceil(log2(this->numOfSets));
    this->indexOffsetTo = this->blockOffsetFrom + 1;
    this->tagOffsetFrom = 63;
    this->tagOffsetTo = this->indexOffsetFrom + 1;

    // reserve vectors before using
    cache.reserve(this->numOfSets);
    for (int x = 0; x < this->numOfSets; ++x) {
      cache[x].valid.reserve(numOfDirs);
      cache[x].tag.reserve(numOfDirs);
      cache[x].directory.reserve(numOfDirs);
      for (int y = 0; y < this->numOfDirs; ++ y) {
        cache[x].directory[y].data.reserve(lineSizeInByte / 8);
      }
    }

    lru.reserve(this->numOfSets);
    for (int i = 0; i < this->numOfSets; ++i) {
      lru[i].lruMatrix.reserve(numOfDirs);
      for (int j = 0; j < this->numOfDirs; ++j) {
        lru[i].lruMatrix[j].reserve(numOfDirs);
      }
    }

    std::cout << "1: " << &lru[0].lruMatrix[0] << std::endl;  // this shows correct memory address space
  }

  void initCache();
  void accessData(uint64_t addr);
  void printLRUMatrix(uint64_t index);

private:
  const uint32_t HIT = 1;
  const uint32_t MISS = 0;
  // cache size list
  uint32_t cacheSizeInKB;
  uint32_t lineSizeInByte;
  uint32_t numOfDirs;
  uint32_t numOfSets;

  // offset list
  uint64_t blockOffsetFrom;
  uint64_t blockOffsetTo;
  uint64_t indexOffsetFrom;
  uint64_t indexOffsetTo;
  uint64_t tagOffsetFrom;
  uint64_t tagOffsetTo;

  std::vector<CacheSet> cache;
  std::vector<LRU> lru;
};

Cache.cpp

void Cache::initCache() {
  for (int x = 0; x < numOfSets; ++x) {
    for (int i = 0; i < numOfDirs; ++i) {
      cache[x].valid[i] = false;
      cache[x].tag[i] = 0;
      for (int j = 0; j < numOfDirs; ++j)
          cache[x].directory[i].data[j] = 0;
    }
  }

  std::cout <<"2: " << &lru[0].lruMatrix[0] << std::endl; // This prints out 0 address in case of L3Cache
  /*
  for (int i = 0; i < numOfSets; ++i) {
    std::cout << "i: " << i << std::endl;
    for (int j = 0; j < numOfDirs; ++j) {
      std::cout << "j: " << j << std::endl;
      for (int k = 0; k < numOfDirs; ++k) {
        std::cout << "k: " << k << std::endl;
        this->lru[i].lruMatrix[j][k] = false;

      }
    }
  }
  */
}

Вывод

1: 0x9464d0
1: 0x9f5190
1: 0xded230
1: 0x140d2d0
2: 0x9464d0
2: 0x9f5190
2: 0
2: 0x140d2d0

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

В случае L3Cache адрес lru [0].lruMatrix [0] отличается между Cache constructor (0xded230) и функцией-членом initCache() (0).

Однако в других случаях, таких как L1Cache, L2Cache, L4Cache, печатается правильный (один и тот же) адрес между constructor и initCache().

Единственное отличие состоит в том, что L3Cache использует numOfDir 16 , который больше, чем другие.

Я не мог понять, почему это происходит.Кажется, в моем коде нет ошибки.

Есть ли проблемы?

1 Ответ

2 голосов
/ 08 июня 2019

Вы читаете lru за пределами.

Если предположить, что больше ничего не коснется Cache::lru до запуска Cache::initCache(), этот std::vector по умолчанию инициализируется в пустом состоянии.Поскольку ничто в этой функции не увеличивает размер lru, при нажатии на эту строку оно все равно остается пустым:

std::cout <<"2: " << &lru[0].lruMatrix[0] << std::endl;

Внутри которого у вас есть lru[0].Это разыменование первого элемента lru, который не существует.Это неопределенное поведение . Может произойти все, что угодно .Не делай этого.Вы должны убедиться, что что-то существует в позиции 0, прежде чем разыменовываете его.

Причина, по которой адрес вектора в lru[0].lruMatrix кажется нулевым, возможно, потому что vector изначально устанавливает егодинамически размещаемый указатель на массив, который будет нулевым указателем.Таким образом, разыменование первого элемента - разыменование нулевого указателя.Это деталь реализации вашего конкретного поставщика стандартной библиотеки;не полагайтесь на это поведение.


Я также вижу следующий код в вашем коде:

lru.reserve(this->numOfSets);
for (int i = 0; i < this->numOfSets; ++i) {
    lru[i].doSomething();
    ...

Это неопределенное поведение по той же причине.std::vector::reserve не меняет размер вектора .Он только выделяет память.Вы, вероятно, хотите std::vector::resize

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