需要帮助解决内存泄漏

时间:2019-10-10 16:45:18

标签: c++ memory-leaks

我正在使用使用对象的动态数组编写库存管理系统。这种策略不是使用向量,而是分配一个动态数组,每次客户需要添加到库存时,动态数组以1递增1。我收到“分段错误”错误,因此我认为这是内存泄漏。

我试图重写它以匹配地址,但没有运气。我认为buildItem函数会产生一个临时对象,该对象在函数结束时会被销毁。我不知道该如何解决。

#include <iomanip>
#include <iostream>
#include <string>
using namespace std;

class InventoryObject {
private:
  int itemNumber;
  string description;
  int qty;
  float price;

public:
  int getItemNum() { return itemNumber; }
  string getDescription() { return description; }
  int getQty() { return qty; }
  float getPrice() { return price; }

  void storeInfo(int p, string d, int q, float pr);
  void showValues(InventoryObject &item);
};

// Function Implementation
void InventoryObject::storeInfo(int p, string d, int q, float pr) {
  itemNumber = p;
  description = d;
  qty = q;
  price = pr;
}

void InventoryObject::showValues(InventoryObject &item) {
  cout << fixed << showpoint << setprecision(2) << endl;
  cout << "Part Number  : " << item.getItemNum() << endl;
  cout << "Description  : " << item.getDescription() << endl;
  cout << "Quantity:    : " << item.getQty() << endl;
  cout << "Price        : " << item.getPrice() << endl << endl;
}

// Function Prototypes for Client Program
InventoryObject buildItem();
void drawMenu();
void showValues(InventoryObject &);
void printInventory(int size);

int main() {
  int size = 1;
  int choice;
  bool quit = false;
  InventoryObject part;
  InventoryObject *iArray = new InventoryObject[size];
  drawMenu();
  cin >> choice;
  while (quit == false) {
    if (choice == 1) {
      InventoryObject item;
      item = buildItem();
      iArray[size] = item;
    }
    if (choice == 2) {
      iArray[size].showValues(iArray[size]);
    }
    if (choice == 3) {
      quit = true;
    }
  }

  return 0;
}

// This function accepts the data from the client and creates a new
// InventoryObject object. The object is then supposed to be added to the
// dynamic array.
InventoryObject buildItem() {
  InventoryObject *tempObject = new InventoryObject;
  int itemNum;
  string description;
  int qty;
  float price;

  cout << "Enter data for the item you want to enter:\n\n";
  cout << "Item Number: \n";
  cin >> itemNum;
  cout << "Description: \n";
  cin.get();
  getline(cin, description);
  cout << "Quantity: \n";
  cin >> qty;
  cout << "Unit price: \n";
  cin >> price;

  tempObject->storeInfo(itemNum, description, qty, price);
  return *tempObject;
}

void drawMenu() {
  cout << "1. Add Inventory\n";
  cout << "2. Display Inventory\n";
  cout << "3. Quit Program\n";
}

我希望创建对象,并将其放入动态数组中。然后重新绘制菜单并从那里与客户进行互动。

4 个答案:

答案 0 :(得分:2)

主要问题的问题是,您正在写的内容超出了为数组(iArray)分配的内存区域。

具体来说,这行代码:

iArray[size] = item;

实际上应该是:

iArray[size - 1] = item;

以上内容不会导致内存泄漏,但是您在程序中执行的其他操作却会导致:

函数buildItem在返回指针的值而没有先删除指针的情况下会执行此操作。

要解决此问题,请更改

InventoryObject *tempObject = new InventoryObject;

InventoryObject tempObject;

最后,请记住在主iArray之前删除return 0;

delete[] iArray

答案 1 :(得分:0)

  1. 使用调试符号(-g标志)构建程序
  2. 运行限制-c无限
  3. 运行程序直到崩溃
  4. 运行gdb core,程序的名称在哪里
  5. 在gdb气候类型中为bt。

您现在应该回溯程序崩溃的地方

答案 2 :(得分:0)

丹尼尔,这是我的观察结果

  1. 函数buildItem必须返回InventoryObject的指针,我的意思是:InventoryObject*。这是因为您正在返回创建时已保留的内存的指针(InventoryObject *tempObject = new InventoryObject;,如下所示:
InventoryObject* buildItem() {
  InventoryObject *tempObject = new InventoryObject;

  //...

  tempObject->storeInfo(itemNum, description, qty, price);
  return *tempObject;
}

  

请记住,您的主数组(InventoryObject *iArray)包含一个指针数组。

  1. 我看到的主要问题。在main中,您使用的是if块,其中有一个称为 item InventoryObject item)的局部变量。让我解释一下:一个类的每个实例,例如您InventoryObject item,如果上下文结束,将被销毁并释放其内存。

因此,在这种情况下,问题在于您正在从函数buildItemreturn *tempObject)返回时转换指针,并将其值存储到局部变量{{1 }},当线程离开InventoryObject item(局部变量的上下文)时释放。

更改局部变量if以处理指针:InventoryObject item

InventoryObject* item
  

我建议您阅读 7章。指针,数组和引用 17 Bjarne Stroustrup C ++编程语言一书中的构造,清理,复制和移动 >。

答案 3 :(得分:0)

  

我试图重写它以匹配地址,但没有运气。我认为buildItem函数会产生一个临时对象,该对象在函数结束时会被破坏。

您的直觉是正确的。此功能有问题,但与临时人员无关。这更多的是关于分配永不破坏的对象。

问题是您正在尝试执行类似于what I was trying to do in this question的操作,但操作不完全相同。即使您正在做我正在做的事情,由于很多人已经比我更好地解释了原因,所以它也不是一个好主意。

问题的根源在于,如果您使用new进行分配,则必须必须使用delete对其进行分配,而您不这样做在这里不做。

InventoryObject buildItem() {
  InventoryObject *tempObject = new InventoryObject;
  //...
  return *tempObject;
}

您只需按值返回对象,而无需先删除它。您甚至都没有通过引用返回它,这会更好(但仍然可能很糟糕:再次参见my question)。您正在分配一个对象,并且永远不会删除它。那是泄漏。

您有两种解决方案:要么直接返回指针(如果您确实需要一个指针),如下所示:

InventoryObject* buildItem() {
  InventoryObject *tempObject = new InventoryObject;
  //...
  return tempObject;
}

或者,您可以像这样简单地按值返回对象:

InventoryObject buildItem() {
  InventoryObject tempObject;
  //...
  return tempObject;
}

鉴于您所显示的代码示例,这是我对两者的推荐。


注意:我要提到的是,如果由于某种原因您确实需要返回一个指针并具有某种具有多态性的工厂方法模式,那么您也可以选择smart pointers。根据其他线程的其他人的建议,我最终完成了该操作。我可以亲自推荐。基本上,您的代码将变成这样:

std::unique_ptr<InventoryObject> buildItem() {
  std::unique_ptr<InventoryObject> tempObject = new InventoryObject; // C++11 way, I think
                  // C++14 and above has a function called make_unique you could use instead.
  //...
  return tempObject;
}

但是,这仅在您像我一样进行某种多态性操作时才有用。给定您到目前为止已发布的代码示例,您实际上只需要根据情况返回值即可。我以为我也提到了这个其他选项,以防万一。


P。 (P.)S.此答案仅与您怀疑的内存泄漏有关。就是说,您还应该注意其他有用的答案。如果您不解决这些问题,其他答案中描述的问题可能会助您一臂之力,并且确实会使您绊倒(实际上,现在仍然可能使您绊倒),因此,我强烈建议您也采纳他们的建议。