内存没有被正确释放

问题描述 投票:0回答:1

我正在处理我的哈希表分配,其中大量数据(从 csv 文件)被读取到哈希表中。此分配的要求是使用指向 DataEntry 类的原始指针(也没有

#include <memory>
库)。 (虽然很讨厌,但还是要跟着)

我大部分都涵盖了它并且程序可以运行,但是当我运行像

valgrind
这样的工具时:

valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --num-callers=20 --log-file=valgrind.log ./main

说明我输了:

==4044056== LEAK SUMMARY:
==4044056==    definitely lost: 17,511,840 bytes in 243,220 blocks
==4044056==    indirectly lost: 1,257,494 bytes in 39,329 blocks
==4044056==      possibly lost: 391 bytes in 6 blocks
==4044056==    still reachable: 20,626 bytes in 292 blocks
==4044056==         suppressed: 0 bytes in 0 blocks

这是我的 CovidDB 类,由于使用单独的链接来避免冲突,哈希表由 2D 向量表示:

  private:
    int size = 17;
    std::vector<std::vector<DataEntry*>> HashTable;

  public:
    inline CovidDB() {
        HashTable.resize(size);
    }

    inline ~CovidDB() {
    for (auto& row : HashTable) {
      for (auto& entry : row) {
        delete entry;
      }
      row.clear();
    }
    HashTable.clear();

    HashTable.shrink_to_fit();
    std::cout << "IN HERE" << std::endl;
    }

我做了一些关于如何从二维向量中删除内存的研究,发现

clear()
删除元素而
shrink_to_fit()
处理内存。更改后我仍然泄漏了很多内存所以我认为我的析构函数没有被调用。

我在析构函数中放了一个

cout
语句,看看它是否被调用了。
"IN HERE"
根本没有打印到终端。

我的教授要求我们的

main.cpp
文件中只有 1 个函数:

#include "CovidDB.h"
#include "run.h"

int main(int argc, char *argv[]) {
  run();
  return EXIT_SUCCESS;
}

这可能是错误的根源吗?有没有不同的方式来处理内存?我如何显式调用析构函数?我试过:

CovidDB dataBase;
dataBase.~CovidDB();

我收到一条错误消息,说没有匹配的运算符。

这是我分配内存的添加函数:

bool CovidDB::add(DataEntry* entry) {
    time_t now = time(0);
    tm* ltm = localtime(&now);
    // DATE FORMAT: mm/dd/yy
    std::string current_date_str = std::to_string(1 + ltm->tm_mon) + "/" + std::to_string(ltm->tm_mday) + "/" + std::to_string(ltm->tm_year % 100);
    std::istringstream iss(current_date_str);
    std::tm current_date = {};
    iss >> std::get_time(&current_date, "%m/%d/%y");

    std::tm entry_date = {};
    std::istringstream iss2(entry -> get_date());
    iss2 >> std::get_time(&entry_date, "%m/%d/%y");

    if (mktime(&current_date) > mktime(&entry_date)) {
        std::cout << "[Record rejected]" << std::endl;
        return false;
    }

    int index = hash(entry -> get_country());
    assert(index < 17 and index >= 0);

    if (HashTable[index].empty()) {
        HashTable[index].push_back(new DataEntry(*entry));
    } else {
        bool added = false;
        for (DataEntry* existing_entry : HashTable[index]) {
            if (hash(existing_entry->get_country()) == hash(entry->get_country()) &&
                existing_entry->get_country() == entry->get_country()) {
                existing_entry->set_c_cases(existing_entry->get_c_cases() + entry->get_c_cases());
                existing_entry->set_c_deaths(existing_entry->get_c_deaths() + entry->get_c_deaths());
                added = true;
                break;
            }
        }
        if (!added) {
            HashTable[index].push_back(new DataEntry(*entry));
        }
    }

    return true;
}

这是我在 main 中调用的“主要”函数

void set_data(DataEntry* data, std::string country, std::string date, int cases, int deaths) {
  data->set_country(get_country(country));
  data->set_date(get_date(date));
  data->set_c_cases(get_covid_cases(cases));
  data->set_c_deaths(get_covid_deaths(deaths));
}

void run() {
  /** DECLARATIONS: */
  std::cout << std::endl << std::endl << std::flush;
  CovidDB dataBase;
  DataEntry *data = new DataEntry;

  std::string country = "\n";
  std::string date = "\0";
  int cases = 0;
  int deaths = 0;

  /** DECLARATIONS: */


  while(true) {
    menu();
    switch(get_input()) {
    case OPID::ID_1: {
      dataBase.add_covid_data(COVID_FILE);
      break;
    }
      
    case OPID::ID_2: {
      set_data(data, country, date, cases, deaths);
      dataBase.add(data); //fix
      break;
    }
      
    case OPID::ID_3: {
      dataBase.get(get_country(country));
      break;
    }
      
    case OPID::ID_4: {
      dataBase.remove(get_country(country));
      break;
    }
      
    case OPID::ID_5: {
      dataBase.display_table();
      break;
    }
      
    case OPID::ID_6: {
      goodbye();
      std::exit(EXIT_SUCCESS);
      break;
    }
      
    default: {
      /** @note do nothing...*/
    }
    }
  }
  std::cout << std::endl << std::endl << std::flush;
}

制作文件:

CXX = g++
CXXFLAGS = -std=c++11 -Wall -Werror -pedantic -O2

SRCS = run.cpp CovidDB.cpp main.cpp
OBJS = $(SRCS:.cpp=.o)
EXEC = main

.PHONY: clean

all: $(EXEC)

$(EXEC): $(OBJS)
    $(CXX) $(CXXFLAGS) $(OBJS) -o $(EXEC)

%.o: %.cpp
    $(CXX) $(CXXFLAGS) -c $< -o $@

clean:
    rm -f $(OBJS) $(EXEC)

项目本身很大,我不想把所有东西都贴在这里。如果我错过的其他一些功能需要进一步分析,请告诉我。

谢谢。

我尝试更改析构函数并尝试调试它,但这只显示了内存分配的位置。我虽然可以在析构函数中删除整个哈希表,但我想不能。

c++ memory destructor
1个回答
0
投票

我看到你有一个析构函数正在删除已分配的哈希条目。但是,您正在执行冗余分配并且没有代码删除在“添加”函数中被拒绝的哈希条目

HashTable[index].push_back([ new DataEntry(*entry) );

指针指向的内存已经分配。再次调用 new 不会将指针的内存转移到新地址。相反,它将分配一个不同的指针到不同的“条目”。您最终会在不同的地址得到两个相同的“条目”

如果析构函数不会清理分配的内存,请务必删除指针。

//In add
hashTable[index].push_back(entry);
//...
if(!added)
{
    //...
    return false;
}


//In run
//...
case OPID::ID_2: {
set_data(data, country, date, cases, deaths);
if(!dataBase.add(data))
{
    delete data;
}
break;
//...
© www.soinside.com 2019 - 2024. All rights reserved.