【问题标题】:How to correctly use smart pointers inside of a class如何在类中正确使用智能指针
【发布时间】:2021-04-18 09:34:31
【问题描述】:

我正在用 C++ 创建一棵二叉树,但在节点类中使用智能指针时遇到了一些问题。 使用普通指针时,一切正常,但使用智能指针时,它就无法正常工作。我认为问题出在插入方法中的这一行:

    '''
    binaryNode* node = this; // This is working
    std::shared_ptr<binaryNode> node {this}; // This throws "double free or corruption" error
    std::shared_ptr<binaryNode> node = shared_from_this (); // This throws "bad weak ptr error", I am correctly inheriting from  enable_shared_from_this
    '''

如何使用智能指针复制binaryNode* node = this;? 我什至尝试成功地使用public std::enable_shared_from_this&lt;binaryNode&gt;。 感谢您的帮助!

编辑: 我会尝试更好地解释自己。这是二叉搜索树的insert() 函数,看起来像这样(这是.cpp 文件):

'''
#include "binarynode.h"

binaryNode::binaryNode(int value){
    this->value = value;
    this->right = nullptr;
    this->left = nullptr;
}

void binaryNode::insert(int value){

binaryNode* node = this;
while(true){
    if(value > node->value){
        if(node->right != nullptr){
            node = node->right;
        }else{
            node->right = new binaryNode(value);
            break;
        }
    }else if(value < node->value){
        if(node->left != nullptr){
            node = node->left;
        }else{
            node->left = new binaryNode(value);
            break;
        }
    }else{
        return;
     }
  }

如何使用智能指针复制它?

编辑 2: 这是我的 .h 文件:

'''
#ifndef BINARYNODE_H
#define BINARYNODE_H

class binaryNode
{
public:
    int value;
    binaryNode(int value);
    binaryNode* right;
    binaryNode* left;
    void insert(int value);
};

#endif // BINARYNODE_H

这是主文件:

#include <iostream>
#include "binarynode.h"

using namespace std;

void printTree(binaryNode* node){
    if(node == nullptr) return;
    cout << node->value << endl;
    printTree(node->left);
    printTree(node->right);
}

int main(){
    binaryNode* bn = new binaryNode(9);
    bn->insert(4);
    bn->insert(20);
    bn->insert(1);
    bn->insert(6);
    bn->insert(15);
    bn->insert(170);
    printTree(bn);
    return 0;
}

【问题讨论】:

  • 再一次,我们需要一个minimal reproducible example。也就是我们可以实际运行的一段代码,并看到与您相同的错误,但尽可能减少。
  • 如果你想使用 shared_from_this(),实际上 `public std::enable_shared_from_this` 是必须的。也就是说,我真的不明白为什么您需要共享 ptr,因为节点拥有子节点,从您的代码中看到的内容不应存在共享所有权。
  • 要遍历树,你不需要智能指针,原始指针应该没问题,因为你没有任何所有权。
  • 我添加了我正在使用的所有代码。使用原始指针很好,但是当我尝试使用智能指针时,我得到了上面提到的错误。

标签: c++ class smart-pointers


【解决方案1】:

您不需要使用 shared_ptr。

实际上,智能指针在这里“解决”对象的所有权,因此当一个对象只有一个所有者时,应该使用 unique_ptr ,而当所有权是共享的时,则使用 shared_ptr 。在您的情况下,所有权是明确的,每个节点拥有其左右成员,因此可以使用 unique_ptr。

对于树遍历问题,不要乱用智能指针,因为您不请求任何所有权,而只是查看值,因此原始指针是可以的。

所以你最终可能会得到这样的结果:

#include <memory>
#include <iostream>

struct binaryNode {
    binaryNode(int value) : value(value) {}
    void insert(int value);

    int value = 0;
    std::unique_ptr<binaryNode> right;
    std::unique_ptr<binaryNode> left;
};

void binaryNode::insert(int value){

    binaryNode* node = this;
    while(true){
        if(value > node->value){
            if(node->right != nullptr){
                node = node->right.get();
            }else{
                node->right = std::make_unique<binaryNode>(value);
                break;
            }
        }else if(value < node->value){
            if(node->left != nullptr){
                node = node->left.get();
            }else{
                node->left = std::make_unique<binaryNode>(value);
                break;
            }
        }else{
            return;
        }
    }
}

void printTree(const binaryNode &node){
    std::cout << node.value << std::endl;
    if (node.left)
        printTree(*node.left);
    if (node.right)
        printTree(*node.right);
}

int main(){
    auto bn = std::make_unique<binaryNode>(9);
    bn->insert(4);
    bn->insert(20);
    bn->insert(1);
    bn->insert(6);
    bn->insert(15);
    bn->insert(170);
    printTree(*bn);
    return 0;
}

你可能注意到 print 不需要带指针,它可以在引用上工作。

【讨论】:

  • 谢谢!这真的帮助了我。当它到达插入函数的末尾时,delete node; 是否安全?我希望尽可能高效地使用内存。
  • 不,您必须不要删除它。正如我告诉你的,这只是一个“导航”树的指针,它不拥有任何东西,因此它不能删除它不拥有的东西。此外,使用 unique_ptr 已经可以在必要时进行删除,因此不应“手动”进行删除。
【解决方案2】:
  1. 您不能多次将同一个原始指针直接转换为共享指针,因为这样您将拥有多个彼此一无所知的所有者,每个所有者都认为它可以完全控制该对象。这就是std::shared_ptr&lt;binaryNode&gt; node {this} 给你双重删除的原因。
  2. 您也不能使用shared_from_this,除非至少有一个共享指针已经指向您的对象。这就是std::shared_ptr&lt;binaryNode&gt; node = shared_from_this () 不起作用的原因。

如果您想要共享指针,请将它们全部共享。例如:

 // binaryNode* bn = new binaryNode(9); <-- nope!
 auto bn = std::make_shared<binaryNode>(9);

 // binaryNode* node = this; <-- nope!
 std::shared_ptr<binaryNode> node = shared_from_this();

我不建议在这里使用共享指针。唯一指针更合适。

【讨论】:

    【解决方案3】:

    C++ 向量可用于支持递归数据结构。使用 smart ptr 要简单得多。基本上在您的 Node 存储矢量子项中作为成员。

    #include <vector>
    
    using std::vector;
    
    
    struct Node {
        Node() = default;
        Node(const Node &) = delete;
        Node(Node &&) = default;
    
        vector<Node> children;
    };
    
    int main()
    {
        Node root;
        root.children.push_back(Node());
        root.children.push_back(Node());
        root.children[0].children.push_back(Node());
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-30
      • 1970-01-01
      相关资源
      最近更新 更多