简体   繁体   English

C ++参考传递

[英]C++ Reference passing

I have been using C# for around a year and have recently been testing my patience with the harsh world of C++. 我已经使用C#大约一年了,最近我正在测试我对C ++苛刻环境的耐心。

I am trying to create an object orientated binary tree. 我正在尝试创建一个面向对象的二进制树。 I have stepped through the code and read up on reference parameter passing and use of const in C++ but cannot work out what I am doing to cause an Access Violation Error. 我已逐步完成代码,并阅读了有关引用参数的传递以及C ++中const的用法,但无法确定我在做什么导致访问冲突错误。 I have ensured that the structure is created properly and the code completes the first line of main as expected, however calling toString seems to result in an error and I cannot work out why. 我已确保正确创建结构,并且代码按预期完成了main的第一行,但是调用toString似乎会导致错误,我无法弄清原因。

Here is the code so far: 这是到目前为止的代码:

// ExpressionCL.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

using namespace std;

template<class TData> class TreeNode
{

private:
    TData Data;
    const TreeNode<TData>* Left = nullptr;
    const TreeNode<TData>* Right = nullptr;

    void setData(TData data)
    {
        Data = data;
    }

public:
    TreeNode<TData>(TData data)
    {
        setData(data);
    }

    TreeNode<TData>(TData data, const TreeNode<TData>& leftNode, const TreeNode<TData>& rightNode)
    {
        setData(data);
        setLeft(leftNode);
        setRight(rightNode);
    }

    void setLeft(const TreeNode<TData>& leftNode)
    {
        Left = &leftNode;
    }

    void setRight(const TreeNode<TData>& rightNode)
    {
        Right = &rightNode;
    }

    TreeNode<TData> getLeft() const
    {
        if (hasLeft())
        {
            return Left;
        }
    }

    TreeNode<TData> getRight() const
    {
        if (hasRight())
        {
            return Right;
        }
    }

    TData getData() const
    {
        return Data;
    }

    bool hasLeft() const
    {
        if (Left != nullptr)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    bool hasRight() const
    {
        if (Right != nullptr)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    string toString() const
    {
        string treeString = "";
        if (hasLeft())
        {
            treeString += Left->toString();
        }
        treeString += to_string(Data);
        if (hasRight())
        {
            treeString += Right->toString();
        }
        return treeString;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    TreeNode<int> IntTree(1, TreeNode<int>(1), TreeNode<int>(2));
    cout << IntTree.toString() << endl;
    return 0;
}

Some guidance or further recommended resources would be great. 一些指导或进一步推荐的资源将是巨大的。

Your setLeft and setRight functions set off alarm bells. 您的setLeftsetRight函数会触发警报声。 Storing the address of an object that was passed by reference is seriously asking for trouble, as the caller may destroy the object and then you are left with dangling pointers for Left and Right . 存储通过引用传递的对象的地址会引起严重的麻烦,因为调用者可能会破坏该对象,然后您剩下的指针分别是LeftRight

In fact that is exactly what you do. 实际上,这正是您要做的。 You pass temporary objects to your constructor, storing their address in Left and Right . 您将临时对象传递给构造函数,并将它们的地址存储在LeftRight Then you call IntTree.toString() which tries to use pointers to objects that no longer exist. 然后,您调用IntTree.toString()尝试使用指向不再存在的对象的指针。


To fix this you need to need to use manual lifetime management for your nodes. 要解决此问题,您需要对节点使用手动生命周期管理。 That means the node must be created via new . 这意味着必须通过new创建节点。 You have the option of either using raw pointers (in which case you would document your interface carefully to note that the caller should call new , pass in the pointer, and not call delete after). 您可以选择使用原始指针(在这种情况下,您将仔细记录您的接口,以注意调用者应调用new ,传入指针,而不是在此之后调用delete )。

The other option is to use smart pointers which will track ownership of the objects, however you have a few other problems to solve before doing that. 另一个选择是使用智能指针,该指针将跟踪对象的所有权,但是在执行此操作之前,您还需要解决其他一些问题。

Specifically, treeNode does not currently follow the Rule of Three . 具体来说, treeNode当前不遵循“三规则” Fixing this is extremely important. 解决此问题非常重要。 At a minimum, disable copying so that you do not accidentally make copies of a treeNode (which will not behave properly until you start following the Rule of Three)). 至少应禁用复制,以免意外复制treeNode副本(直到您开始遵循“三则规则”后,它才能正常工作)。

Using smart pointer classes means you can follow Rule of Zero instead of Rule of Three which makes for much cleaner code (although it may be difficult to do straight off the bat if you're new to C++, there aren't any good online teaching resources that I know of besides SO). 使用智能指针类意味着您可以遵循零规则而不是三规则,这样可以使代码更简洁(尽管如果您是C ++的新手,可能很难直接做到这一点,但是没有很好的在线教学方法我知道的其他资源)。

You are calling the Treenode constructor with temporary values and storing in the treenode pointer to these temps. 您正在使用临时值调用Treenode构造函数,并将其存储在指向这些临时文件的treenode指针中。 After the constructor has finished, these temps are gone and in calling a function which uses pointers to those temps (toString), a crash is occurring. 构造函数完成后,这些临时性消失了,并且在调用使用指向这些临时性的指针的函数(toString)时发生崩溃。

Your design needs the values of the treeitems as long as the tree is used, because you store only pointers to those values in the tree. 只要使用树,您的设计就需要树项的值,因为您仅将指向这些值的指针存储在树中。 You could change the design to store copies of the treenodes within the tree. 您可以更改设计以将树节点的副本存储在树中。

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

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