【问题标题】:deallocation of pointers指针的释放
【发布时间】:2010-11-11 04:05:14
【问题描述】:

我有一个 A 类型的列表指针(称为 ListA)容器一个指针 B 的向量。(每个 A 对象都是一个具有私有属性的容器类:std<vector> *B)。然后,我声明一个指针(称为C,与A具有相同的类型),通过ListA进行for循环以获取所有指针B并将它们放入C中。当我退出程序时,我先释放ListA,然后释放ListA他们自己的指针向量 B。然后我释放指针 C,但程序崩溃了。

我对此进行了一些调试,并且知道释放时指针 C 指向任何内容,因此它不知道要释放什么。

我做错了吗?或者我的问题有什么解决方案?

对不起,我会把我的代码放在下面

//Class A
#pragma once

#include "MyContainer.h"
class B;
class A
{
public:
    A();
    ~A();
    MyContainer<B> *pListOfB;
}

A::A()
{
    pListOfB = new MyContainer<B>;
}
A::~A()
{
    if(pListOfB)
    {
        delete pListOfB;
        pListOfB = NULL;
    }
}
//Class C
#pragma once

#include "MyContainer.h"
class B;
class C
{
public:
    C();
    ~C();
    MyContainer<B> *pListOfB;
    void getListOfB(MyContainer<A> *pListOfA);
}

C::C()
{
    pListOfB = new MyContainer<B>;
}
C::~C()
{
    if(pListOfB)
    {
        delete pListOfB;
        pListOfB = NULL;
    }
}
void C::getListOfB(MyContainer<A> *pListOfA)
{
    for(pListOfA->isBegin(); !pListOfA->isEnd();)
    {
        A *pA = pListOfA->getNext();
        for(pA->isBegin(); !pA->isEnd();)
        {
            B* pB = pA->*pListOfB->getNext();
            pListOfB->add(pB);
        }
    }
}
//Class MyContainer
#pragma once

#include <vector>

template <class T> 
class MyContainer
{
public:
    MyContainer(void);
    ~MyContainer(void);
    T* getNext();
    void removeAll();
    void add(T* t);
    void isBegin();
    bool isEnd();   
private:
    std::vector<T*> items;  
    typename std::vector<T*>::iterator it;
};

template <class T> MyContainer<T>::~MyContainer()
{
    removeAll();
}

template <class T> void MyContainer<T>::add(T *t)
{
    items.push_back(t);
}

template <class T> void MyContainer<T>::removeAll()
{
    while(!isEmpty())
    {
        std::vector<T*>::iterator tempIt =items.begin();
        T* t = (*tempIt);
        items.erase(tempIt);
        delete t;
        t=NULL;
    }
}

template <class T>
T* MyContainer<T>::getNext()
{
    if(isEnd() || isEmpty())
        return NULL;    
    return (T*)(*(it++));
}

template <class T>
void MyContainer<T>::isBegin()
{
    it = items.begin();
}

template <class T>
bool MyContainer<T>::isEnd()
{
    return it==items.end();
}

我执行以下操作: 1.初始化一个列表A对象:MyContainer *pListOfA; 2.向pListOfA中的每个A对象插入B数据 3.初始C对象 4.调用C对象操作getListOfB从pListOfA中获取B数据。 5. 退出程序

程序先dealloc pListOfA,每个A再dealloc自己的pListOfB。之后程序dealloc C 对象依次dealloc c 的pListOfB 属性。但是pListOfB 指向任何内容,因为pListOfA 会dealloc 每个数据。所以我的程序崩溃了。 我通过 rem 修复了 C 类 dtor 中的 delete pListOfB 行,但我在该行收到警告内存泄漏。 这都是我的问题。请告诉我正确的方法。提前致谢。

【问题讨论】:

  • 是的,你做错了什么;否则您的程序不会崩溃。但是,从上面的描述中推断出你做错了什么是非常困难的。我建议展示一个重现问题的最小程序。
  • 一个std&lt;vector&gt; *B?你确定吗?
  • 是的,没有代码,诸如“A 类型的列表指针”之类的东西真的很混乱。
  • 我刚刚添加了我的简化代码。

标签: c++ pointers stl


【解决方案1】:
  • 首先,你分配
  • 然后您“取放”某处(不是分配,只是复制指针)
  • 然后你解除分配
  • 然后你解除分配。 ...等等

【讨论】:

  • 换句话说,您将一个列表的内容复制到另一个列表,但实际上并没有克隆对象。这些列表引用相同的对象。因此,当您删除第一个列表的对象时,您也会删除第二个列表引用的对象。删除第二个列表然后双重删除一个对象并崩溃。
【解决方案2】:

正确的方法是不要使用纯指针

在你开始写delete pointer;的那一刻,你必须重新考虑你是否真的需要那个指针,如果你确实需要它,是否没有一些预先打包的智能指针类可以承担内存管理的负担来自你。

您发布的示例代码可以完全不使用指针编写:

//Class A
#pragma once

#include "MyContainer.h"
#include "B.h"

class A
{
public:
    A() { };
    ~A() { };
    MyContainer<B> ListOfB;
};

//Class C
#pragma once

#include "MyContainer.h"
#include "B.h"

class C
{
public:
    C() { };
    ~C() { };
    MyContainer<B> ListOfB;
    void getListOfB(MyContainer<A>& ListOfA);
};

void C::getListOfB(MyContainer<A>& ListOfA)
{
    for(ListOfA.isBegin(); !ListOfA.isEnd();)
    {
        A& anA = ListOfA.getNext();
        for(anA.ListOfB.isBegin(); !anA.ListOfB.isEnd();)
        {
            B aB = anA.ListOfB.getNext();
            ListOfB.add(aB);
        }
    }
}

//Class MyContainer
#pragma once

#include <vector>

template <class T> 
class MyContainer
{
public:
    MyContainer(void);
    ~MyContainer(void) { };
    T& getNext();
    void removeAll();
    void add(const T& t);
    void isBegin();
    bool isEnd();   
private:
    std::vector<T> items;  
    typename std::vector<T>::iterator it;
};

template <class T> void MyContainer<T>::add(const T& t)
{
    items.push_back(t);
}

template <class T> void MyContainer<T>::removeAll()
{
    items.clear();
}

template <class T>
T& MyContainer<T>::getNext()
{
    if(isEnd() || isEmpty())
        return throw std::out_of_range("");
    return *it++;
}

template <class T>
void MyContainer<T>::isBegin()
{
    it = items.begin();
}

template <class T>
bool MyContainer<T>::isEnd()
{
    return it==items.end();
}

如果需要在 A 类和 C 类之间共享 B 实例(A 和 C 中的列表都引用相同的 B 对象),那么您可以将 shared pointers 存储在列表中。

【讨论】:

  • 感谢您的帮助,我会试试看
  • 三个A B C 类背后的想法是在A 类和C 类之间同步数据。这意味着当A 类或C 类更改B 类时,另一个类会知道该更改。所以我决定A类和C类指向相同的数据。但是经过几天的测试和思考,我意识到我试图做的事情会导致内存泄漏。我绝对必须使用指针在我的项目中传递参数。所以我的即时想法是每个类 A 或 C 都会存储一个类 B 的副本,每次我对一个类的数据进行更改时,我也必须对另一个类进行更改。你知道解决我的问题的更好方法吗?
  • @ducva:是的:使用boost::shared_ptr(或者std::shared_ptr,如果你有的话)。 shared_ptr 类将为您处理内存管理,并且专门为两个类需要共享某些公共数据的所有权的情况而设计。
  • 这是一个很好的建议,但它没有回答为什么现有代码不起作用。它还引入了一个新问题:包含类型中的任何资源的生命周期。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-11
  • 2014-10-09
相关资源
最近更新 更多