C++ C+中的安全删除+;
我开发了一个基于数组的哈希表实现,其中包含几个股票名称、符号、价格等。我需要从阵列中移除一个库存。我被告知使用delete操作符是糟糕的面向对象设计。什么是好的面向对象的删除设计C++ C+中的安全删除+;,c++,C++,我开发了一个基于数组的哈希表实现,其中包含几个股票名称、符号、价格等。我需要从阵列中移除一个库存。我被告知使用delete操作符是糟糕的面向对象设计。什么是好的面向对象的删除设计 bool hash::remove(char const * const symbol, stock &s, int& symbolHash, int& hashIndex, int& usedIndex) { symbolHash = this->hashStr( symbol
bool hash::remove(char const * const symbol, stock &s,
int& symbolHash, int& hashIndex, int& usedIndex)
{
symbolHash = this->hashStr( symbol ); // hash to try to reduce our search.
hashIndex = symbolHash % maxSize;
usedIndex = hashIndex;
if ( hashTable[hashIndex].symbol != NULL &&
strcmp( hashTable[hashIndex].symbol , symbol ) == 0 )
{
delete hashTable[hashIndex].symbol;
hashTable[hashIndex].symbol = NULL;
return true;
}
for ( int myInt = 0; myInt < maxSize; myInt++ )
{
++usedIndex %= maxSize;
if ( hashTable[usedIndex].symbol != NULL &&
strcmp( hashTable[usedIndex].symbol , symbol ) == 0 )
{
delete hashTable[usedIndex].symbol;
hashTable[usedIndex].symbol = NULL;
return true;
}
}
return false;
}
这确实有效,但是会导致内存泄漏。即使如此,我也不确定这是不是一个好的面向对象的设计
这是我的标题,股票和所有这些东西都是在这里初始化和定义的
//hash.h
private:
friend class stock;
int isAdded; // Will contain the added hash index.
// Test for empty tables.
// Can possibly make searches efficient.
stock *hashTable; // the hashtable will hold all the stocks in an array
};
//哈希表选择器
hash::hash(int capacity) : isAdded(0),
hashTable(new stock[capacity]) // allocate array with a fixed size
{
if ( capacity < 1 ) exit(-1);
maxSize = capacity;
// We can initialize our attributes for the stock
// to NULL, and test for that when searching.
for ( int index = 0; index < maxSize; index++ )
{
hashTable[index].name = NULL;
hashTable[index].sharePrice = NULL;
hashTable[index].symbol = NULL;
}
}
我的问题仍然是,如何进行安全移除
s = &hashTable[usedIndex];
delete s.symbol;
s.symbol = NULL;
hashTable[usedIndex] = &s;
这似乎可行,但会导致内存泄漏!这是如何安全完成的
删除哈希表[usedIndex]。符号;
哈希表[usedIndex]。符号=NULL 看起来您正在使用(或试图使用)带线性探测的开放寻址来解决冲突。在这种情况下,您需要以某种方式将项目标记为已删除(而不是空),以便您仍然可以访问位于已删除项目之后的项目。否则,您将无法查找某些项目,因为如果您的探测序列发现已删除的bucket,它将提前终止。因此,您将无法再访问表中的某些项,这可能就是内存泄漏的原因 基本上,您应该从散列索引开始,将该项与您的键进行比较,然后如果它不等于您的键,则递增到下一个索引并重复,直到找到该项,或者直到遇到一个空桶为止。如果找到该项目,请删除该项目并将该索引标记为已删除。但重要的是,您有一些方法来区分空哈希桶和已删除的哈希桶,否则已删除的哈希桶将导致您提前终止探测序列
至于“良好的面向对象设计”,面向对象编程的固有特性并不一定会使使用
delete
成为糟糕的设计。每个分配内存的数据结构都必须以某种方式释放内存。您可能指的是这样一个事实:实现不管理自己内存的类通常更安全,工作量更少,而是将该职责委托给预先制作的容器类,如std::vector
或std::string
看起来您正在使用(或试图使用)使用线性探测打开寻址以解决冲突。在这种情况下,您需要以某种方式将项目标记为已删除(而不是空),以便您仍然可以访问位于已删除项目之后的项目。否则,您将无法查找某些项目,因为如果您的探测序列发现已删除的bucket,它将提前终止。因此,您将无法再访问表中的某些项,这可能就是内存泄漏的原因
基本上,您应该从散列索引开始,将该项与您的键进行比较,然后如果它不等于您的键,则递增到下一个索引并重复,直到找到该项,或者直到遇到一个空桶为止。如果找到该项目,请删除该项目并将该索引标记为已删除。但重要的是,您有一些方法来区分空哈希桶和已删除的哈希桶,否则已删除的哈希桶将导致您提前终止探测序列
至于“良好的面向对象设计”,面向对象编程的固有特性并不一定会使使用
delete
成为糟糕的设计。每个分配内存的数据结构都必须以某种方式释放内存。您可能指的是这样一个事实:实现不管理自己内存的类通常更安全,工作量更少,而是将该职责委托给预先制作的容器类,如std::vector
或std::string
,以获得良好的面向对象设计,集合应该不知道其中存储了什么。这实际上与使用delete
操作符本身无关,但是需要一个对象(在本例中是您的stock
)来存储特定于数据结构的代码是非常困难的
我可以看到两个快速解决此问题的计划
stock*
数组,而不仅仅是stock
。空值表示插槽打开,非空值表示插槽可以使用。在该计划中,您将在插入整个stock
对象时调用new和delete,然后在删除对象时调用,这比符号更面向对象stock
项目的HashSlot
类,添加所需的簿记值。
然后,您的哈希表将是一个包含HashSlot
项的数组我喜欢第二种。在任何一种情况下,
stock
都应该有一个析构函数来清除自己的内部内存。要获得良好的面向对象设计,集合应该不知道其中存储了什么。这实际上与使用delete
操作符本身无关,但是需要一个对象(在本例中是您的stock
)来存储特定于数据结构的代码是非常困难的
我可以看到两个快速解决此问题的计划
stock*
数组,而不仅仅是stock
。空值表示插槽打开,非空值表示插槽可以使用。在该计划中,您将在插入整个stock
对象时调用new和delete,然后在删除对象时调用,这比符号更面向对象stock
项目的HashSlot
类,添加所需的簿记值。
然后,您的哈希表将是一个包含HashSlot
项的数组股票
都应该
private:
const static int maxSize; // holds the capacity of the hash table minus one
date priceDate; // Object for the date class. Holds its attributes.
char *symbol;
char *name;
int sharePrice;
};
s = &hashTable[usedIndex];
delete s.symbol;
s.symbol = NULL;
hashTable[usedIndex] = &s;
hash::hash(int capacity) // change this to unsigned and then you can't have capacity < 0
: isAdded(0)
, hashTable(0) // don't call new here with bad parameters
{
if ( capacity < 1 ) exit(-1); // this should throw something, maybe bad_alloc
maxSize = capacity;
hashTable = new stock[capacity]; // this calls the stock() constructor
// constructor already called. All this code is useless
// We can initialize our attributes for the stock
// to NULL, and test for that when searching.
// for ( int index = 0; index < maxSize; index++ )
// {
// hashTable[index].name = NULL;
// hashTable[index].sharePrice = NULL;
// hashTable[index].symbol = NULL;
// }
}
class stock {
char* name; // these should be std::string as it will save you many headaches
char* sharePrice; // but I'll do it your way here so you can see how to
char* symbol; // avoid memory leaks
public:
stock() : name(0), sharePrice(0), symbol(0) {}
~stock() { delete[] name; delete[] sharePrice; delete[] symbol; }
setName(const char* n) { name = new char[strlen(n)+1]; strcpy(name, n); }
setPrice(const char* p) { sharePrice = new char[strlen(p)+1]; strcpy(sharePrice, p); }
setSymbol(const char* s) { symbol = new char[strlen(s)+1]; strcpy(symbol, n); }
const char* getName() const { return name; }
const char* getPrice() const { return sharePrice; }
const char* getSymbol() const { return symbol; }
}