为什么类中的向量自动变为NULL

时间:2019-06-08 20:03:14

标签: c++ class vector

我正在创建简单的缓存模型以模拟某些应用程序。

但是,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]的地址在缓存constructor(0xded230)和成员函数initCache()(0)之间是不同的。

但是,其他情况(例如L1Cache,L2Cache,L4Cache)会在constructorinitCache()之间打印正确的(相同)地址。

唯一的区别是L3Cache使用的 numOfDir 16 比其他的大。

我不知道为什么会这样。看来我的代码没有错。

有什么问题吗?

1 个答案:

答案 0 :(得分:2)

您正在越界阅读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