简体   繁体   English

如何正确使用 class 内部的智能指针

[英]How to correctly use smart pointers inside of a class

I am creating a binary tree in C++, and I have some problems when using smart pointers inside of the node class.我在 C++ 中创建二叉树,在节点 class 内部使用智能指针时遇到一些问题。 When using normal pointers, everything works fine, but with smart pointers it is just not working.使用普通指针时,一切正常,但使用智能指针时,它就无法正常工作。 I think that the problem is in this line in the insert method:我认为问题出在插入方法中的这一行:

    '''
    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
    '''

How can I replicate binaryNode* node = this;如何复制binaryNode* node = this; with smart pointers?用智能指针? I even tried to use public std::enable_shared_from_this<binaryNode> usuccessfully.我什至尝试成功地使用public std::enable_shared_from_this<binaryNode> Thanks for your help!谢谢你的帮助!

Edit: I will try to explain myself a little bit better.编辑:我会尝试更好地解释自己。 This is the insert() function of a binary search tree, that looks like this (this is the.cpp file):这是二叉搜索树的insert() function,如下所示(这是 .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;
     }
  }

How can I replicate this using smart pointers?如何使用智能指针复制它?

Edit 2: This is my.h file:编辑 2:这是 my.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

And this is the main file:这是主文件:

#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;
}
  1. You cannot directly convert the same raw pointer to a shared pointer more than once, because then you will have several owners that know nothing about each other, each one thinking it has full control over the object.您不能多次将相同的原始指针直接转换为共享指针,因为这样您将有几个彼此一无所知的所有者,每个所有者都认为它可以完全控制 object。 This is why std::shared_ptr<binaryNode> node {this} gives you a double-delete.这就是为什么std::shared_ptr<binaryNode> node {this}给你一个双重删除。
  2. You also cannot use shared_from_this unless there is at least one shared pointer already pointing to your object.你也不能使用shared_from_this除非至少有一个共享指针已经指向你的 object。 This is why std::shared_ptr<binaryNode> node = shared_from_this () doesn't work.这就是std::shared_ptr<binaryNode> node = shared_from_this ()不起作用的原因。

If you want shared pointers, make them all shared.如果您想要共享指针,请将它们全部共享。 For example:例如:

 // 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();

I do not recommend using shared pointers here though.我不建议在这里使用共享指针。 Unique pointers are more appropriate.唯一指针更合适。

You do not need to use shared_ptr<>.您不需要使用 shared_ptr<>。

Actually smart pointer are here to 'solve' ownership on object, thus when an object has a single owner, unique_ptr<> should be used, and when ownership is shared, shared_ptr are used.实际上,智能指针在这里“解决” object 的所有权,因此当 object 有一个所有者时,应该使用 unique_ptr<>,当所有权共享时,使用 shared_ptr。 In you situation, the ownership is clear, each node owns its left and right members, thus unique_ptr can be used.在你的情况下,所有权是明确的,每个节点都拥有它的左右成员,因此可以使用 unique_ptr 。

For the tree traversal problem, don't mess with smart pointers as you are not requesting any ownership, but just looking at values, thus raw pointers are ok.对于树遍历问题,不要弄乱智能指针,因为您不请求任何所有权,而只是查看值,因此原始指针是可以的。

So you may end up with something like this:所以你最终可能会得到这样的结果:

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

You may notice that the print does not need to take a pointer, it can work on reference.您可能会注意到 print 不需要使用指针,它可以在引用上工作。

C++ vector can be used to support recursive data structure. C++ 向量可用于支持递归数据结构。 It's much simpler that use smart ptr.使用 smart ptr 要简单得多。 Basicly In your Node store vector children as a member.基本上在您的节点中存储向量子项作为成员。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM