在现代C++;或者在这种特殊情况下也可以 我知道,除非真正需要,否则必须避免在现代C++中生出指针(或者更准确地说是代码 /代码>和删除>代码>。我相信当涉及到图形实现时,指针是非常有用的。不过,我很高兴听到对这方面的评论

在现代C++;或者在这种特殊情况下也可以 我知道,除非真正需要,否则必须避免在现代C++中生出指针(或者更准确地说是代码 /代码>和删除>代码>。我相信当涉及到图形实现时,指针是非常有用的。不过,我很高兴听到对这方面的评论,c++,pointers,reference,c++17,C++,Pointers,Reference,C++17,我正在玩二进制搜索树和编写insert函数。我使用两种不同但相似的方法实现,一种使用指针,另一种使用指针引用。很明显,我想更改指针本身(参照ptr)。想知道它们是否有优点,或者不应该使用,必须使用常量引用或智能指针(现代方式)编写 我知道除非真正需要,否则必须避免现代C++中的指针。 事实并非如此。您可能听到的是,如果您的需求符合标准化模式/解决方案,例如unique\u ptr,您应该避免使用原始(裸)指针 很明显,我想更改指针本身(参照ptr)。想知道它们是否有优点,或者不应该使用,并且必须

我正在玩二进制搜索树和编写
insert
函数。我使用两种不同但相似的方法实现,一种使用指针,另一种使用指针引用。很明显,我想更改指针本身(参照ptr)。想知道它们是否有优点,或者不应该使用,必须使用常量引用或智能指针(现代方式)编写

我知道除非真正需要,否则必须避免现代C++中的指针。 事实并非如此。您可能听到的是,如果您的需求符合标准化模式/解决方案,例如
unique\u ptr
,您应该避免使用原始(裸)指针

很明显,我想更改指针本身(参照ptr)。想知道它们是否有优点,或者不应该使用,并且必须使用const reference(现代方式)编写

如果您想拥有输出参数,可以通过多种方式实现:

  • 返回值
  • 对值的引用(作为参数)
  • 指向值的指针(作为参数)
  • struct
    std::tuple
    或使用结构化绑定中返回多个值
  • 成员变量(仅适用于类中的成员函数)
  • 全局变量
对于所有情况,没有单一的最佳方法。您使用哪一个取决于您以及如何使用该函数。在某些情况下,它还取决于项目的编码风格指南(例如,在引用与指针的情况下)。例如:

  • 如果只有一个输出参数,有些人更喜欢使用返回值
  • 有些库更喜欢将返回值专门用于错误代码
  • 一些编码风格指南避免引用,因为它们希望在调用方中明确看到您正在传递地址(例如
    f(a)
    f(&a)
  • 在成员函数中,通常使用成员变量
  • 在几乎所有情况下,您都应该避免使用全局变量

必须使用常量引用(现代方式)编写


顺便说一下,请注意,您没有编写
const
引用,只是对
note*
的引用。它不是“现代C++”:引用是第一个C++标准的一部分。

< P>代码>,除非真正需要的< /COD>错了,否则必须避免现代C++中的指针。p> 应避免使用
new
delete
,而应使用唯一和共享指针

但如果不转移所有权,您仍将通过引用或原始指针传递对象

您的
节点
具有所有权关系,因此应该是:

struct Node
{
    int data;
    std::unique_ptr<Node> left;
    std::unique_ptr<Node> right;
};
由于您不打算更改它,我将使用const ref:

void display(const Node &root)
{
    if(root.left != nullptr) {
        display(*root.left);
    }

    cout << root.data << " ";

    if(root.right != nullptr) {
        display(*root.right);
    }
}
insert_ref_to_ptr
函数类似于:

std::unique_ptr<Node> create(int data)
{
    auto node = std::make_unique<Node>();
    node->data = data;
    return std::move(node);
}
void insert_ref_to_ptr(std::unique_ptr<Node> &root, int data)
{
    if (root == nullptr)
        root = std::move(create(data));
    else if (data < root->data)
        insert(root->left, data);
    else
        insert(root->right, data);
}
void insert_ref_to_ptr(std::unique_ptr&root,int数据)
{
if(root==nullptr)
root=std::move(创建(数据));
else if(数据data)
插入(根->左,数据);
其他的
插入(根->右,数据);
}

绝对不是一个好的设计。所有这些函数都应该在类中,左指针和右指针都应该是唯一的指针。除非你100%确定自己需要它们,否则你绝对应该避免使用原始指针。@MatthieuBrucher绝对正确。但是我不关心这里的设计。这个问题的要点是什么?你是问二叉树、封装还是好的C++实践?如果要新建/删除,必须完全封装它。不过,您没有理由在此处执行新建/删除操作。您自己的
insert
函数会是什么样子?非常有兴趣了解您将如何实现整个操作。如果你能做到这一点,那将是非常有教育意义和帮助的。@KarimSole我将如何实现该树,取决于用例。但您的问题更多的是关于是否应该使用指针,以及引用和对指针的引用。是的,这是应该的,但是你用它做什么总是很重要的。我建议你看一看谈话(或其他关于他或提图斯·温特的谈话)当然,先生。对于我的具体案例,我非常有兴趣了解一位经验丰富的开发人员如何处理这个简单的用例。请你在最后一部分努力一下好吗。非常感谢。是我误解了什么,还是
display
在这里引用是错误的?树结构的常见模式是叶节点将
设置为
nullptr
,在这种情况下,
display
中需要的解引用将调用UB。(root!=NULL检查也没有什么意义。)基本上没有偏好或最佳实践?!就一般情况而言,不,不是真的。确实很有帮助。如果您有机会用自己的风格编写
insert
函数,我会非常激动。很好奇专家会如何编写这样的案例。@KarimSole在C中,您的第一个接口可能是最流行的解决方案(返回指针)。在C++中,几乎每个人都会设计一个类来封装数据结构(参见C++标准库的例子)——因此,<代码> INSERT /CODE>将是一个成员函数。
void display(Node *root)
{
    if (root != nullptr)
    {
        display(root->left);
        cout << root->data << " ";
        display(root->right);
    }
}
void display(const Node &root)
{
    if(root.left != nullptr) {
        display(*root.left);
    }

    cout << root.data << " ";

    if(root.right != nullptr) {
        display(*root.right);
    }
}
std::unique_ptr<Node> create(int data)
{
    auto node = std::make_unique<Node>();
    node->data = data;
    return std::move(node);
}
void insert_ref_to_ptr(std::unique_ptr<Node> &root, int data)
{
    if (root == nullptr)
        root = std::move(create(data));
    else if (data < root->data)
        insert(root->left, data);
    else
        insert(root->right, data);
}