2013-10-07 102 views
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]中的向量中的对象。

我的问题是我听到说每个新的都有一个删除。我必须在哪里删除这个对象?实际上我并没有计划删除程序中创建的任何商店或客户对象。

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

非常感谢。

回答

0

每次用new创建对象时,都会从堆中取出一块内存。只有通过new得到的指针才能与此内存通信。当您在该指针上使用delete时,内存被释放并可能被用于其他目的。所以当你丢失指针时,你会产生内存泄漏。
在您的代码中,正确的方法是:
从具有空指针的向量开始。 当你在确切的位置创建对象检查指针。如果不是空你已经有了对象,并有将其删除(或者抛出错误)

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]; 
    } 
} 
+0

很酷。所以你的意思是像vSlot(100,NULL)而不是vSlot(100)?然后,我替换它检查与if语句,如果它的NULL,如你所示? – user2856452

+0

没有矢量已经用空值初始化它。但是当你有原始的poiters时,你应该用null(它写好的方法)来初始化它们。对不起我错误(和正确答案)在你创建函数。你检查指针是否存在空对象。 – conf1ict

+1

当'CreateCustomer()'删除一个现有的项目时,如果后续的'new'产生一个异常,你应该将该向量的那个空置空。 –

3

以您编写代码的方式,您应该扩展您为gShop的析构器实现,以迭代vector<> vSlotdelete每个元素。由于您必须以这种方式管理内存以防止内存泄漏,因此您还需要遵循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

+0

你应该修改'>>'到'>>'。另外,提到深度复制的工作也很好。 – Cramer

+0

@Cramer没有什么可以解决的。 'std :: shared_ptr'是C++ 11,因此在没有空格的情况下在一行中关闭几个模板>> >>是非常好的。 – syam

+0

谢谢,我听说过boost,使用它的许多功能 - 尤其是快速迭代向量元素 - 会很可爱 - 但我有一个旧版本的代码块,它没有它。我不知道如何安装它,当我开始升级到更新的版本时,我的程序不再运行(我有很多OPENGL在里面),这些错误似乎一般都没有解决:/我认为它是一个很好的尽管如此。 – user2856452

0

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

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); 
} 

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

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; 
+0

是的,应该是“2” - 输入时出错。我实际上并不想删除vSlot的任何元素,因为我宁愿填充“虚拟”客户。我没有得到shared_ptr?这是一个新的C++语法吗?我几年前开始使用旧版本和OpenGL一起开发整个程序。它有几千行代码。我坚持使用那个版本,我相信并且不能使用shared_ptr。 – user2856452

+0

['shared_ptr'](http://en.cppreference.com/w/cpp/memory/shared_ptr)在C++ 11中是新的。对于旧版本的C++,您可以使用['boost :: shared_ptr'](http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm)。 –

+0

我甚至没有提高我的包括!我不能让代码与更新的版本一起工作..我没有得到编译错误,但真正令人讨厌的与OpenGL构建错误。当我研究它时,它被保持为未解决。所以我继续使用旧代码。 – user2856452

相关问题