我编写了一个小软件并希望在堆上创建一个新对象。因此,在类成员函数中我有
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;
...
}
并且在main中我调用成员函数来创建新客户..
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]内的向量。
我的问题是我听到这样的说法:每一个新的都有删除。我在哪里删除这个对象?我实际上并不打算删除程序中任何创建的商店或客户对象。
其次,这个代码到目前为止还没有引起内存泄漏吗?我有点担心我在成员函数类中创建了新对象,所以我应该尝试在析构函数中实现delete到gShop并将指针设置为NULL - 在理论情况下我应该想删除shop [0] ?
非常感谢。
答案 0 :(得分:3)
在您编写代码的方式中,您应该扩展gShop
的析构函数实现,以迭代vector<> vSlot
和delete
每个元素。因为您必须以这种方式管理内存以防止内存泄漏,所以您还需要遵循Rule of Three。因此,您还需要在复制构造期间执行某些操作(深层复制),并且您必须为赋值运算符执行某些操作(清理即将复制的vector<>
,并做一个深刻的复制)。
您可以避免这些问题,并允许您的对象使用默认的析构函数,复制构造函数和赋值运算符,而不是使用智能指针。例如:
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
。
答案 1 :(得分:0)
是的,必须释放从堆分配的任何内存! 使用“new”,您将从堆中分配内存,即gCustomer的sizeof。 释放内存的好地方是你的析构函数:~gShop() 内存泄漏是由于没有释放内存造成的,尽管一旦关闭程序,所有内存都会自动释放。
答案 2 :(得分: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];
}
}
答案 3 :(得分: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
的{{1}}广告位中存储了两个单独的vSlot[1]
个对象,因此您正在失去对某个客户的跟踪。我怀疑你的意思是这样做:
vShop[0]
话虽这么说,你应该重新思考你的设计并让STL为你处理所有的内存管理,例如:
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;
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);
}