(注意:我是新手。)我有一个函数可以创建一个双链接列表,其中包含Representative*的DNode,每个Representation有3个对象(字符串名称、int访问次数、int捐赠次数),并且内存泄漏。
运行程序后,我收到以下内存泄漏消息:
https://textuploader.com/51tme
我在valgrind的记忆检查中也有类似的错误。在我创建新Representative的5次中,每条消息似乎都被触发了两次(总共有10次内存泄漏)。列出的函数始终是addToList()中的运算符new。下面是addToList()函数:
bool ListManager::addToList(string rep_list){
istringstream convertRepresentative(rep_list);
string whitespaces(" tfvnr");
size_t found = rep_list.find_first_not_of(whitespaces);
if (rep_list.empty() || found == string::npos){
/* string is empty or only has whitespace */
cout << "n| ERROR(addToList()): String is empty. No representatives added to list.n| Function halted.n";
return false;
}
string name;
int visits;
int donations;
Representative* temp; // comment out if using shared_ptr
if (convertRepresentative.fail()){
/* error in string input */
cout << "n| ERROR(addToList()): Could not import string. No representatives added to list.n| Function halted.n";
convertRepresentative.clear();
return false;
}
else{
while (!convertRepresentative.eof()){
if (!(convertRepresentative >> name)){
cout << "n| ERROR(addToList()): Could not import string. Incorrect format.n| No representatives added to list. Function halted.n";
rep_list.clear();
convertRepresentative.clear();
return false;
}
if (!(convertRepresentative >> visits)){
cout << "n| ERROR(addToList()): Could not import string. Incorrect format.n| No representatives added to list. Function halted.n";
rep_list.clear();
convertRepresentative.clear();
return false;
}
if (!(convertRepresentative >> donations)){
cout << "n| ERROR(addToList()): Could not import string. Incorrect format.n| No representatives added to list. Function halted.n";
rep_list.clear();
convertRepresentative.clear();
return false;
}
temp = new Representative(name, visits, donations);
ListDLL.insertTail(temp);
//shared_ptr<Representative> temp;
//temp.reset(new Representative(name, strength, speed));
//RosterDLL.insertTail(&*temp);
}
convertRepresentative.clear();
return true;
}
}
我假设我将在某个时刻删除temp,但删除temp会删除DNode内的Representative数据。所以我不知道什么时候该删除temp和/或重置/清除它,不管怎样。正如你在我的注释代码中看到的,我尝试过智能指针,但它们做了我刚才描述的事情——它们从DNode中删除了所需的信息。
我是新手&我知道你们对格式等要求很严格(很抱歉我的#includenamespacestd)。我希望这是一个简单的解决方案。请帮忙。
编辑:根据建议,这里是DoubleLinkedList.h(您可以在第一个链接中看到该项目使用的所有文件):
#ifndef DOUBLELINKEDLIST_H_
#define DOUBLELINKEDLIST_H_
#include <stdexcept>
#include <iostream>
#include "Representative.h"
using namespace std;
struct DNode{
Representative* rep;
DNode* next;
DNode* prev;
DNode(Representative*& rep,
DNode* prev_val = NULL, DNode* next_val = NULL) :
rep(rep), next(next_val), prev(prev_val) {}
};
template<class T>
class DoubleLinkedList
{
public:
DNode* head;
DNode* tail;
int count;
DoubleLinkedList() :
head(NULL), count(0),
tail(NULL){
}
virtual ~DoubleLinkedList() {
clear();
}
bool find(Representative* rep){
bool found = false;
if (head == NULL) {
return found;
}
DNode* DNode_ptr = head;
while (DNode_ptr != NULL){
if (DNode_ptr->rep == rep){
found = true;
}
DNode_ptr = DNode_ptr->next;
}
return found;
}
void insertTail(Representative* rep) {
if (find(rep) == false) {
if (head == NULL) {
DNode* newDNode = new DNode(rep);
head = newDNode;
count++;
return;
}
else {
DNode* temp = head;
while (temp->next != NULL) {
temp = temp->next;
}
DNode* tailDNode = new DNode(rep);
temp->next = tailDNode;
tailDNode->next = NULL;
tailDNode->prev = temp;
count++;
return;
}
}
else {
return;
}
}
Representative* at(int index){
DNode* temp_ptr = head;
if (index < 0 || index > count - 1){
throw out_of_range("Out of Range");
}
else {
for (int i = 0; i < index; i++){
temp_ptr = temp_ptr->next;
}
return temp_ptr->rep;
}
}
int size(){
return count;
}
void clear(){
DNode* temporary_ptr = head;
while (temporary_ptr != NULL){
DNode* tmp_pointer = temporary_ptr;
temporary_ptr = temporary_ptr->next;
delete tmp_pointer;
}
count = 0;
head = NULL;
return;
}
//Rest of functions omitted
};
#endif /* DOUBLELINKKEDLIST_H_ */
啊,我现在看到了。分配一个Representative
,然后将分配的指针存储在分配的DNode
中。当您clear
和DoubleLinkedList
时,这将删除DNodes
,但不会删除存储在其中的已分配的Representatives
,这会导致泄漏。
更好的解决方案是在列表中存储Representative
,而不是Representative *
。
如果你能在C++11下编译,考虑到编译器对它的高度支持,你应该能够,你根本不应该使用原始指针来管理内存。
如果您不想传输大量数据,并且正在创建自己的类,那么您甚至不需要首先使用指针。只需实现move构造函数和move-assignment运算符,并使用常规值对象而不是指向它们的指针。
如果您真的需要使用指针——例如,可以创建某种库的对象集合,即没有实现move构造函数和move-assignment运算符的对象——请使用<memory>
标头中的std::unique_ptr<T>
或std::shared_ptr<T>
。您不需要调用delete,因为智能指针会处理它。