【问题标题】:My C++ database class appears to be leaking memory [closed]我的 C++ 数据库类似乎正在泄漏内存 [关闭]
【发布时间】:2022-01-12 17:13:30
【问题描述】:

我创建了一个数据库类,基本上将 kvp id 的哈希值保存到指针。这是课程:

#ifndef _DATABASE_H_
#define _DATABASE_H_

#include <vector>
#include <list>
#include <map>

using std::vector;
using std::list;
using std::map;
using std::pair;

template <class T>
class Database
{
public:
    Database();
    virtual ~Database();

    virtual T* operator[](int itemID);

    virtual int addItem(T* newItem);
    virtual int addItem(T* newItem, int itemID);
    virtual bool deleteItem(int itemID);
    virtual T* removeItem(int itemID);          //removes from database but leaves item in memory
    virtual T* getItem(int itemID);
    virtual const T* getItem(int itemID) const;

    virtual void clear();

    virtual int numItems() const;

    virtual int size() const;

private:
    typedef map<int, T*> ContainerType;

    ContainerType data;
    unsigned int numItems_;
};

template <class T>
Database<T>::Database()
{
}

template <class T>
Database<T>::~Database() 
{
    this->clear();
}

template <class T>
T* Database<T>::operator [](int itemID)
{
    return data[itemID];
}

template <class T>
int Database<T>::addItem(T* newItem)
{
    if(newItem == NULL)
        return -1;

    int id = static_cast<int>(data.size());
    pair< ContainerType::iterator, bool> result = data.insert( ContainerType::value_type(id, newItem) );

    ++numItems_;

    return (*(result.first)).first;
}

template <class T>
int Database<T>::addItem(T* newItem, int itemID)
{
    if(newItem == NULL)
        return -1;

    data[itemID] = newItem;
    ++numItems_;

    return itemID;
}

template <class T>
T* Database<T>::getItem(int itemID)
{
    if(itemID < 0 || itemID >= size())
        return NULL;

    return data[itemID];
}

template <class T>
const T* Database<T>::getItem(int itemID) const
{
    if(itemID < 0 || itemID >= size())
        return NULL;

    ContainerType::const_iterator i = data.find(itemID);
    if(i == data.end())
        return NULL;
    
    return (*i).second;
}

template <class T>
void Database<T>::clear()
{
    ContainerType::iterator i;
    for(i = data.begin(); i != data.end(); ++i)
    {
        T* item = (*i).second;

        delete item;
        item = NULL;
    }

    numItems_ = 0;
}

template <class T>
bool Database<T>::deleteItem(int itemID)
{
    T* item = data[itemID];

    if(item)
    {
        delete item;
        data[itemID] = NULL;
        data.erase(itemID);
        return true;
    }
    --numItems_;

    return false;
}

template <class T>
T* Database<T>::removeItem(int itemID)
{
    if(itemID < 0 || itemID > size()-1)
        return NULL;

    T* item = data[itemID];
    data[itemID] = NULL;
    data.erase(itemID);

    --numItems_;

    return item;
}

template <class T>
int Database<T>::numItems() const
{
    return numItems_;
}

template <class T>
int Database<T>::size() const
{
    return static_cast<int>(data.size());
}

#endif

它大部分都有效,但它似乎正在泄漏内存,我不确定我哪里出错了。有什么建议吗?

【问题讨论】:

  • #define _DATABASE_H_ 该名称是为语言实现保留的。通过定义它,您的程序的行为将是未定义的。您应该使用另一个标头保护。
  • 谁负责免费物品?如果您添加两个具有相同 id 的项目会发生什么?
  • 为什么你认为它似乎在泄漏内存?
  • 如果不使用newmalloc 系列的成员之一来分配动态内存,程序很难出现泄漏。您更有可能遇到问题,因为程序没有为 map&lt;int, T*&gt; ContainerType 的实例分配任何动态内存来指向。
  • 我的建议是将 T* 替换为 std::shared_ptr 以便自动删除不再引用的 T 对象。

标签: c++ templates


【解决方案1】:

由于在某些情况下您需要数据库调用delete item,因此您需要确保不会覆盖项目:

  1. addItem(T*):从data.size()生成id,不保证唯一。例如。序列addItem(ptr1)addItem(ptr2)deleteItem(0)addItem(ptr3) 将赋予ptr3ptr2 相同的id,并覆盖它。 建议:int id = data.empty() ? 0 : data.rbegin()-&gt;first + 1;。基本上,这会查看地图中最大的 id 并将其增加 1。

  2. addItem(T*,int): 不检查是否覆盖现有元素。如果它覆盖了一个,它不应该删除原始项目吗?

  3. deleteItem(int)T* item = data[id]。如果id 不存在,则会返回nullptr,但它也会在您的地图中添加一个元素(id,nullptr)

【讨论】:

    【解决方案2】:

    可能使此代码看起来好像在泄漏内存的一个问题是Database&lt;T&gt;::deleteItem 错误地维护了类不变量,其中numItems_ 是对象中非空项的数量。如果被删除的项存在,则成员函数在递减numItems_之前返回。

    Database&lt;T&gt;::removeItem 另一方面是正确的。一般来说,我在这段代码中看到的一个样式问题是删除逻辑在太多地方重复,这导致了这样的错误。尝试根据removeItem 实现deleteItem:make delete 删除该项目,然后将其删除。然后在您删除的任何地方使用deleteItem,例如在clear()

    【讨论】:

      猜你喜欢
      • 2021-09-14
      • 2021-10-01
      • 2011-06-28
      • 1970-01-01
      • 2016-01-27
      • 2013-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多