【问题标题】:Error EXC_BAD_ACCESS in list with SmartPointer带有 SmartPointer 的列表中出现错误 EXC_BAD_ACCESS
【发布时间】:2016-05-13 17:29:51
【问题描述】:

当我从列表中删除一个元素时,我遇到了这个问题。

这是我的清单.h:

class AwesomeList {
friend class Iteratore;
private:
class Nodo;

class SmartPointer {
public:
    Nodo* punt;

    SmartPointer(Nodo* n = 0): punt(n) {}
    SmartPointer(const SmartPointer& ptr): punt(ptr.punt) {}
    ~SmartPointer() {
        delete punt;
    }

    SmartPointer& operator=(const SmartPointer& ptr) {
        if (this != &ptr) {
            delete punt;
            punt = ptr.punt;
        }
        return *this;
    }
    bool operator==(const SmartPointer& ptr) const {
        return ptr.punt == punt;
    }
    bool operator!=(const SmartPointer& ptr) const {
        return ptr.punt != punt;
    }
    Nodo* operator->() const {
        return punt;
    }
    Nodo& operator*() const {
        return *punt;
    }
};

class Nodo {
public:
    T* value;
    SmartPointer next;

    Nodo(T* t = T(), const SmartPointer& ptr = SmartPointer()): value(t), next(ptr) {}
};

SmartPointer head;
SmartPointer tail;

public:
class Iteratore{
    friend class AwesomeList;
private:
    AwesomeList::SmartPointer punt;
public:
    bool operator==(const Iteratore& it) const {
        return it.punt == punt;
    }
    bool operator!=(const Iteratore& it) const {
        return it.punt != punt;
    }
    Iteratore& operator++() {
        if(punt != 0) punt = punt->next;
        return *this;
    }
    Iteratore& operator++(int) {
        if(punt != 0) punt = punt->next;
        return *this;
    }
    T* operator*() const {
        if (punt != 0) return punt->value;
    }
};

AwesomeList(const SmartPointer& ptr = 0): head(ptr), tail(0) {
    if (head != 0) {
        SmartPointer p = head;
        while (p != 0)
            p = p->next;
        tail = p;
    }
}
AwesomeList(const AwesomeList& list): head(list.head), tail(list.tail) {}

AwesomeList& operator=(const AwesomeList& list) {
    head = list.head;
    tail = list.tail;
}

int getSize() const {
    int count = 0;
    SmartPointer p = head;
    while (p != 0) {
        p = p->next;
        count++;
    }
    return count;
}
bool isEmpty() const {
    return getSize() == 0;
}
T* at(int pos) const {
    if (pos > -1 && pos < getSize()) {
        SmartPointer p = head;
        while (pos--) {
            p = p->next;
        }
        return p->value;
    } else return 0;
}
void add(const T& t) {
    if (head == 0) {
        head = SmartPointer(new Nodo(&(const_cast<T&>(t))));
        tail = head;
    } else {
        tail->next = SmartPointer(new Nodo(&(const_cast<T&>(t))));
        tail = tail->next;
    }
}
void remove(int pos) {
    if (pos > -1 && pos < getSize()) {
        SmartPointer newHead = head;
        SmartPointer p = newHead;
        head = 0;
        while (pos--) {
            add(*p->value);
            p = p->next;
        }
        p = p->next;
        while (p != 0) {
            add(*p->value);
            p = p->next;
        }
    }
}
void replace(int pos, T* t) {
    if (pos > -1 && pos < getSize()) {
        SmartPointer p = head;
        while (pos--)
            p = p->next;
        p->value = t;
    }
}
void replace(int pos, const T& t) {
    if (pos > -1 && pos < getSize()) {
        SmartPointer p = head;
        while (pos--)
            p = p->next;
        T& t_obj = const_cast<T&>(t);
        p->value = &t_obj;
    }
}

Iteratore begin() const {
    Iteratore it;
    it.punt = head;
    return it;
}
Iteratore end() const {
    Iteratore it;
    it.punt = 0;
    return it;
}
T* operator[](const Iteratore& it) const {
    return it.punt->value;
}
};

这是我做的测试:

AwesomeList<int> list = AwesomeList<int>();
list.add(1);
list.add(2);
list.add(3);
for (int i = 0; i < list.getSize(); i++)
    qDebug() <<*(list.at(i)) <<" ";

list.remove(-1);
for (int i = 0; i < list.getSize(); i++)
    qDebug() <<*(list.at(i)) <<" ";

list.remove(2);
for (int i = 0; i < list.getSize(); i++)
    qDebug() <<*(list.at(i)) <<" ";

list.replace(0, 5);
qDebug() <<"Replace in posizione 0";
auto cit = list.begin();
for (; cit != list.end(); cit++)
    qDebug() <<*(*cit) <<" ";

qDebug() <<"Size";
qDebug() <<list.getSize() <<endl;

这是出现错误的行:

  • AwesomeList::Nodo::~Nodo() + 16 (awesomelist.h:8)
  • AwesomeList::SmartPointer::~SmartPointer() + 42 (awesomelist.h:21)
  • AwesomeList::SmartPointer::~SmartPointer() + 21 (awesomelist.h:22)

感谢您的帮助。谢谢!

更新

我解决了像这样更改 SmartPointer 和 Nodo 类的问题:

SmartPointer(Nodo* n = 0): punt(n) {
        if (punt) punt->references++;
    }
    SmartPointer(const SmartPointer& ptr): punt(ptr.punt) {
        if (punt) punt->references++;
    }
    ~SmartPointer() {
        if (punt) {
            punt->references--;
            if (punt->references == 0) delete punt;
        }
    }

    SmartPointer& operator=(const SmartPointer& ptr) {
        if (this != &ptr) {
            Nodo* n = punt;
            punt = ptr.punt;
            if (punt) punt->references++;
            if (n) {
                n->references--;
                if (n->references == 0) delete n;
            }
        }
        return *this;
    }
    bool operator==(const SmartPointer& ptr) const {
        return ptr.punt == punt;
    }
    bool operator!=(const SmartPointer& ptr) const {
        return ptr.punt != punt;
    }
    Nodo* operator->() const {
        return punt;
    }
    Nodo& operator*() const {
        return *punt;
    }
};

class Nodo {
public:
    T* value;
    SmartPointer next;
    int references;

    Nodo(T* t = T(), const SmartPointer& ptr = SmartPointer()): value(t), next(ptr), references(0) {}
};

【问题讨论】:

  • 您的错误列表实际上并没有列出错误是什么...
  • 错误是EXC_BAD_ACCESS。
  • 我的朋友,我认为你是想愚弄我们。 SmartPointer head; 不能仅使用 SmartPointer 的前向声明进行编译。您需要 SmartPointer 的完整定义来实例化 SmartPointer
  • Nodo 显然应该是一个模板,但没有声明为模板。我认为你在 class AwesomeList 之前放弃了 template&lt;class T&gt;
  • @user4581301,程序编译好了,别着急。我为错误 EXC_BAD_ACCESS 寻求帮助。模板 存在。我没有包含在消息中,因为它造成了问题。

标签: c++ macos qt memory-leaks smart-pointers


【解决方案1】:

抱歉,我不明白你的SmartPointer 类下面的比率。

它带有一个指向 Nododelete 的指针以及构造函数。很好。

但是,如果我没记错的话

(1) 当您使用复制构造函数创建SmartPointer 时,您从复制的SmartPointer 复制指针,因此您有两个具有相同值的punt 对象;当你销毁这两个对象时,你在同一个指针上调用delete 两次;这可能会使程序崩溃

(2) 当你调用operator= 时,你的复制构造函数也有同样的问题,但是你并没有删除旧的指向值

例如看add()

    head = SmartPointer(new Nodo(&(const_cast<T&>(t))));
    tail = head;

您创建一个临时的SmartPointer 对象,并使用new Nodo(&amp;(const_cast&lt;T&amp;&gt;(t))) 对其进行初始化。接下来将这个临时对象复制到head 中,因此head 和临时对象都携带相同的非NULL 指针。现在临时对象被销毁了,所以punt指向的内存被删除了,但是head(他的punt)继续指向一个被删除的内存区域。现在您将head 复制到tail 中,并且headtail 都指向同一个已删除区域。

看else情况

    tail->next = SmartPointer(new Nodo(&(const_cast<T&>(t))));
    tail = tail->next;

在这种情况下,tail-&gt;next(并考虑到take 指向已删除区域)接收来自删除它的临时对象的指针。因此,您在已删除区域中写入了一个立即删除的指针。

我希望清楚这一切有多危险。

建议:重新设计SmartPointer 类。

ps:对不起,我的英语不好。

【讨论】:

  • 你已经很清楚了。谢谢!在您看来,如果我使用私有字段 SmartPointer* head,然后我写 head = new SmartPointer(...),可以解决我的问题吗?
  • 想一想其中的逻辑。您想创建一个指向智能指针的原始指针。这破坏了智能指针的要点。马克思是正确的。您需要重新实现SmartPointer,使其变为rule of 5 compliantuse move semantics。另一种选择是use std::unique_ptr 而不是SmartPointer
  • 是的,你说得对。有什么建议吗? PS:我已经用正确的 operator=. 更新了我的代码
  • @ Daniele - 是的,检查你是否正在复制一个对象本身是好的。但主要问题仍然存在:SmartPointer 可以有多个实例,punt 的值相同,因此,您可能会删除两次或更多次同一个指针。
  • @Daniele - 我想你正在开发这段代码来练习 C++(否则,我的建议是:使用std::list,如果你可以使用 C++11,std::shared_ptr)所以我建议(只是为了玩 C++):在Nodo 中添加一个计数器并将其初始化为零;每次将Nodo 指针复制到SmartPointer 时,都会增加指向节点中的计数器;每次从SmartPointe(赋值运算符中的析构函数和旧值)释放指针时,递减节点计数器并验证值;仅当计数器(递减后)为零时才调用delete。只是为了玩 C++。
猜你喜欢
  • 2014-05-31
  • 2018-05-21
  • 2022-01-27
  • 1970-01-01
  • 2018-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-19
相关资源
最近更新 更多