我正在处理我的哈希表分配,其中大量数据(从 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(¤t_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(¤t_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)
项目本身很大,我不想把所有东西都贴在这里。如果我错过的其他一些功能需要进一步分析,请告诉我。
谢谢。
我尝试更改析构函数并尝试调试它,但这只显示了内存分配的位置。我虽然可以在析构函数中删除整个哈希表,但我想不能。
我看到你有一个析构函数正在删除已分配的哈希条目。但是,您正在执行冗余分配并且没有代码删除在“添加”函数中被拒绝的哈希条目
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;
//...