簡體   English   中英

為什么在使用shared_ptr時出現此運行時異常?

[英]why am i getting this runtime exception when using shared_ptr?

在下面的代碼中,返回1之后,我得到了以下運行時異常(可能是內存泄漏); 並在Node()的析構函數中。

Unhandled exception at 0x0f9bad4a (msvcp100d.dll) in test.exe: 0xC0000005: Access violation reading location 0xfeeefef2.

自從我使用smart_ptr以來已經有一段時間了,所以我在嘗試了解我在做什么錯嗎?

#include <vector>
#include <queue>
#include <memory>

#include <iostream>
using namespace std;

class Node;
typedef shared_ptr<Node> SharedNode;

class Node {
    Node* parent;
    vector< SharedNode > children;
    int value;

    //limiting construction
    Node(int a_value):value(a_value),parent(0){}
    Node(const Node &copy); //non-construction-copyable
    Node& operator=(const Node& copy); //non-copyable
public:
    static SharedNode create(int a_value){
        return SharedNode(new Node(a_value));
    }
    SharedNode addChild(SharedNode child){
        child->parent = this;
        children.push_back(child);
        return child;
    }

SharedNode getNode(int searchValue);
};

SharedNode Node::getNode(int searchValue){

    // Breadth First Search
    queue<SharedNode> que;
    que.push(SharedNode(this));

    while(!que.empty()){
        SharedNode node = que.front();
        que.pop();

        if(node->value == searchValue)
            return node;

        vector<SharedNode>::iterator it;
        for(it = node->children.begin(); it != node->children.end(); it++){
            que.push(*it);
        }
    }

    return 0;
}

int main(){
    SharedNode node_ptr = Node::create(5);

    for(int i  = 0; i < 4; ++i)
        node_ptr->addChild(Node::create(i));

    cout << (node_ptr->getNode(-1) != 0 ? "Found" : "Not found");

    return 1;
}

我想在此上使用shared_ptr時會搞砸,例如: shared_ptr(this) 但是那是我的猜測。

我在這里做錯了什么?

問題出在

que.push(SharedNode(this));

這將創建一個現在擁有this的新共享指針。 但是,由於create()方法,存在另一個擁有相同對象的共享指針。 這可能導致雙重刪除。

如果在這種情況下有理由使用共享指針,則正確的解決方案是enable_shared_from_this

首先,將節點定義更改為此。

class Node : public std::enable_shared_from_this<Node> { ...

然后將違規行更改為

que.push(this->shared_from_this());

這將導致它返回一個指向該對象的shared_ptr,但是它與已經存在的shared_ptr共享,而不是成為兩個單獨的shared_ptr對象。

注意,為了合法使用this->shared_from_this() ,該對象必須由shared_ptr擁有。 您已經通過靜態create()方法完成了此操作,但是我想確保您了解該限制。

編輯: shared_ptr所有權的簡要說明。

使用構造函數從原始指針創建shared_ptr ,它將創建一個引用對象,該對象既包含指向該對象的指針又包含引用計數,該引用計數用於確定有多少shared_ptr對象指向該對象。 然后,將指向該引用對象的指針傳遞到該原始shared_ptr所創建的所有副本,其中引用計數跟蹤引用了多少shared_ptr對象。

當你調用shared_ptr(this) ,是沒有辦法的共享指針要知道, this是另一個共享指針擁有,並創建一個新的參考對象。 一旦其中一個達到零引用計數,盡管另一個shared_ptr參考對象仍指向該對象,該對象將被刪除,從而導致指針懸空和您看到的錯誤。

如果僅在父級存在時才需要子級存在,則可以考慮將Node更改為僅具有其他Node的std::vector (刪除指針)。 當最高級別的節點通過其析構函數銷毀時,它將銷毀向量,從而銷毀子節點,依此類推。

class Node
{
  // whatever operations you need... 

  std::vector<Node> children;
}

編輯:根據要求...

如果您有一個用例,您確實想讓孩子們比父母長壽,那么您就必須處理父母指針,因為它可能在孩子之前被銷毀。 一種快速的解決方案是確定您是否確實需要父指針,如果不需要,則將其消除。

但是,假設您仍要保留它,則不能在此處使用shared_ptr 如果這樣做,您將具有循環依賴關系,並且兩者都不會被自動銷毀,這不是您想要的。

解決方案是使用std::weak_ptr 基本上,它以不防止破壞指向對象的方式與shared_ptr引用對象進行交互。

class Node
{
private:
   std::weak_ptr<Node> parent;
   // Other constructors.  
   Node(int a_value):value(a_value),parent() {} 
public:
   SharedNode addChild(SharedNode child){
        child->parent = this->shared_from_this(); // Initialize their pointer using
                                                  // your shared pointer
        children.push_back(child);
        return child;
   }
   // This function will return a shared_ptr to nullptr (and will evaluate false) 
   // if you have no parent, or if the parent node has been deleted
   SharedNode getParent()
   {
       return parent.lock();
   }
};

考慮以下代碼會發生什么:

Node * dumb_ptr = new Node;
shared_ptr<Node> smart1 = dumb_ptr;
shared_ptr<Node> smart2 = dumb_ptr;

現在,您有兩個智能指針,它們都認為它們擁有相同的對象。 其中一個將要刪除該對象,而另一個將在某個時候嘗試使用或刪除該已刪除的對象。 解決此問題的方法是始終從另一個智能指針或new創建一個智能指針。 最好不要使用任何愚蠢的指針-包括this指針。

shared_ptr<Node> smart1 = new Node;
shared_ptr<Node> smart2 = smart1;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM