0

我编写了一个小软件,想在堆上创建一个新对象。因此,在类成员函数中

void  gShop::CreateCustomer(int type, int number)
    {
    vSlot[number] = new gCustopmer(type);
    vSlot[number]->itsContactToShop=itsShopNumber;
    vSlot[number]->itsNumber=number;
    }

其中 vSlot 是指向客户对象的指针向量。我有一个(这里:缩写)类 gShop,本质上是:

class gShop : public gBranch
   {
   public:
       gShop(): vSlot(100){}
      ~gShop(){}   

       std::vector <gCustomer*>   vSlot;
       ...
   }

主要是我调用成员函数来创建新客户..

  vShop[0].CreateCustomer(TYPE_M20, 1);
  vShop[0].CreateCustomer(TYPE_F40, **2**);//EDIT:typo previously here. I intend to create customers by reading a file later on.

  std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
  std::cout<< "2" << vShop[0].vSlot[2]->itsTypeString << std::endl;

我知道我已经在“堆”上创建了“新”两个对象(如果我正确处理术语 - 抱歉,我对没有受过正规教育的编程很陌生)而且我还有两个指向存储在向量中的对象的指针对象商店[0]。

我的问题是我听说过这样的说法,即每一个新的都有一个删除。我必须在哪里删除这个对象?我实际上不打算删除程序中任何创建的商店或客户对象。

其次,就不会导致内存泄漏而言,这段代码到目前为止还可以吗?我有点担心我在成员函数类中创建了新对象,所以我应该尝试在 gShop 的析构函数中实现 delete 并将指针设置为 NULL - 在理论上我应该想要删除 shop[0] ?

非常感谢。

4

4 回答 4

3

以您编写代码的方式,您应该扩展您的析构函数实现以gShop迭代每个元素。因为您必须以这种方式管理内存以防止内存泄漏,所以您还需要遵循三原则。因此,您还需要在复制构建期间做一些事情(深拷贝),并且您必须为赋值运算符做一些事情(清理即将被复制的内容,并进行深拷贝)。vector<> vSlotdeletevector<>

您可以通过使用智能指针来避免这些问题,并允许您的对象使用默认析构函数、复制构造函数和赋值运算符。例如:

    std::vector<std::shared_ptr<gCustomer>> vSlot;

在 中创建元素时vSlot,可以使用make_shared()

    vSlot[number] = std::make_shared<gCustopmer>(type);

当不再引用内存时,智能指针将为您删除内存。如果您没有可用的 C++.11,则可以boost::shared_ptr改用。

智能指针将使您的副本与复制gShop的原始指针共享相同的指针gShop。智能指针使这种情况很好,因为不会delete对同一内存进行多次调用。但是,如果您需要深拷贝语义,那么您仍然需要实现自己的拷贝构造函数和赋值运算符来制作深拷贝。

如果您想要像智能指针一样自动清理的东西,但仍然使用默认复制构造函数和默认赋值运算符为您提供深层副本,那么您可以尝试使用boost::optional.

如果您使用的是g++4.4 或更高版本,那么您应该能够使用 启用 C++.11 功能-std=gnu++0x,或者-std=c++0x如果您不想要 GNU 扩展。如果您有g++4.7 或更高版本,则选项为-std=gnu++11-std=c++11

于 2013-10-07T23:10:48.760 回答
0

是的,必须释放从堆中分配的任何内存!使用“新”,您将从 gCustomer 大小的堆中分配内存。释放内存的好地方是在你的析构函数中: ~gShop() 内存泄漏是由于没有释放你的内存造成的,尽管一旦你关闭你的程序,所有的内存都会自动释放。

于 2013-10-07T23:12:05.437 回答
0

每次创建对象时new,都会从堆中获取一块内存。与此内存通信的唯一方法是通过您从new. 当您delete在该指针上使用时,内存将被释放并可用于其他目的。因此,当您丢失指针时,您会造成内存泄漏。
在您的代码中,正确的方法是:
从带有空指针的向量开始。当您在精确位置创建对象时检查指针。如果它不是 null 你已经有对象并且必须删除它(或者可能抛出错误)

void  gShop::CreateCustomer(int type, int number)
{
    if(vSlot[number] != 0) {
         delete vSlot[number];
         vSlot[number] = 0;
    }
    vSlot[number] = new gCustopmer(type);
    vSlot[number]->itsContactToShop=itsShopNumber;
    vSlot[number]->itsNumber=number;
}

当向量被销毁时,您需要释放其中的所有内存。所以你的析构函数将是这样的:

gShop::~gShop() {
    for(int i = 0; i < (int)vSlot.size(); ++i) {
          delete vSlot[i];
    }
}
于 2013-10-07T23:14:18.400 回答
0

gShop需要它创建delete的对象。gCustomer它可以在其析构函数中做到这一点,例如:

class gShop : public gBranch
{
public:
    ...
    ~gShop()   
    ...
};

gShop::~gShop()
{
    std::vector<gCustomer*>::iterator iter = vSlot.begin();
    std::vector<gCustomer*>::iterator end = vSlot.end();
    while (iter != end)
    {
        delete *iter;
        ++iter
    }
}

或者:

void deleteCustomer(gCustomer *customer)
{
    delete customer;
}

gShop::~gShop()
{
    std::for_each(vSlot.begin(), vSlot.end(), deleteCustomer);
}

但是,您仍然会有内存泄漏。您将两个单独gCustomer的对象存储在 的同一个vSlot[1]插槽中vShop[0],因此您正在失去对其中一位客户的跟踪。我怀疑你打算这样做:

vShop[0].CreateCustomer(TYPE_M20, 1);
vShop[0].CreateCustomer(TYPE_F40, 2); // <-- was previously 1

std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
std::cout<< "2" << vShop[0].vSlot[2]->itsTypeString << std::endl;

话虽如此,您应该重新考虑您的设计并让 STL 为您处理所有内存管理,例如:

class gShop : public gBranch
{
public:
    std::vector <gCustomer> vSlot;
    ...
};

void gShop::CreateCustomer(int type)
{
    vSlot.push_back(type);
    gCustomer &cust = vSlot.back();
    cust.itsContactToShop = itsShopNumber;
    cust.itsNumber = vSlot.size()-1;
}

vShop[0].CreateCustomer(TYPE_M20);
vShop[0].CreateCustomer(TYPE_F40);


// remember that vectors are 0-indexed
std::cout<< "0" << vShop[0].vSlot[0].itsTypeString << std::endl;
std::cout<< "1" << vShop[0].vSlot[1].itsTypeString << std::endl;

或者:

class gShop : public gBranch
{
public:
    std::vector <std::shared_ptr<gCustomer> > vSlot;
    ...
};

void gShop::CreateCustomer(int type)
{
    std::shared_ptr customer = std::make_shared<gCustomer>(type);
    customer->itsContactToShop = itsShopNumber;
    customer->itsNumber = vSlot.size();
    vSlot.push_back(customer);
}

vShop[0].CreateCustomer(TYPE_M20);
vShop[0].CreateCustomer(TYPE_F40);

std::cout<< "0" << vShop[0].vSlot[0]->itsTypeString << std::endl;
std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
于 2013-10-07T23:26:51.163 回答