我应该避免在现代C ++中引用指针还是在这种特殊情况下还可以

时间:2019-02-03 19:16:50

标签: c++ pointers reference c++17

我知道,除非确实需要,否则必须避免使用现代C ++中的原始指针(或更准确地说是newdelete)。我相信在图形实现方面,指针非常有用。我很乐意听到对此的评论。

我正在研究二进制搜索树并编写insert函数。我使用两种不同但相似的方法实现,一种使用指针,另一种使用对指针的引用。显然,我想更改指针本身(参考ptr)。想知道它们中的任何一个是否有优势,或者不应该使用它们,而必须使用const引用或智能指针(现代方式)编写。

Node *insert_ptr(Node *root, int data)
{
    if (root == NULL)
        return create(data);
    else if (data < root->data)
        root->left = insert(root->left, data);
    else
        root->right = insert(root->right, data);
    return root;
}

void insert_ref_to_ptr(Node *&root, int data)
{
    if (root == NULL)
        root = create(data);
    else if (data < root->data)
        insert(root->left, data);
    else
        insert(root->right, data);
}

如果您要运行,我将在下面提供其余代码。您可能要使用1 3 6 8 10 14 13 4 7作为输入

struct Node
{
    int data;
    Node *left;
    Node *right;
};

void display(Node *root)
{
    if (root != NULL)
    {
        display(root->left);
        cout << root->data << " ";
        display(root->right);
    }
}

Node *create(int data)
{
    Node *node = new Node();
    node->data = data;
    node->left = node->right = NULL;
    return node;
}

int main()
{
    Node *root = NULL;
    vector<int> nodes;

    string line;
    int value;
    getline(cin, line);
    stringstream split(line);
    while (split >> value)
        nodes.push_back(value);
    /*
    root = insert_ptr(root, nodes[0]);
    for (int i = 1; i < nodes.size(); i++)
        insert_ptr(root, nodes[i]);
    */

    for (int i = 0; i < nodes.size(); i++)
        insert_ref_to_ptr(root, nodes[i]);
    display(root);
    return 0;
}

2 个答案:

答案 0 :(得分:3)

  

我知道除非真正需要,否则必须避免使用现代C ++中的指针。

那是不对的。您可能会听到的是,如果您的要求符合标准化的模式/解决方案,例如unique_ptr,则应避免使用原始(裸露的)指针。

  

很显然,我想更改指针本身(参考ptr)。想知道它们中的任何一个是否有优点,或者不应该使用它们,而必须使用const reference(现代方式)编写。

如果要具有输出参数,则有很多方法可以实现:

  • 返回值。
  • 引用值(作为参数)。
  • 指向值的指针(作为参数)。
  • structstd::tuple或使用结构化绑定的多个返回值。
  • 成员变量(仅适用于类中的成员函数)。
  • 全局变量。

在所有情况下都没有一种最佳方法。您使用哪一种取决于您,以及如何使用该功能。在某些情况下,它还取决于项目的编码样式准则(例如,在引用还是指针的情况下)。例如:

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

  

必须使用const引用(现代方式)编写。

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

答案 1 :(得分:2)

that pointers in modern C++ must be avoided unless really needed是错误的。

newdelete应该避免,而应该使用唯一和共享的指针。

但是,如果您不跨领域所有权,您仍然会通过引用或原始指针传递对象。

Node具有所有权关系,因此应为:

struct Node
{
    int data;
    std::unique_ptr<Node> left;
    std::unique_ptr<Node> right;
};

struct Node
{
    int data;
    std::shared_ptr<Node> left;
    std::shared_ptr<Node> right;
};

您的display函数不需要所有权,因此您将节点作为指针(或引用)传递

void display(Node *root)
{
    if (root != nullptr)
    {
        display(root->left);
        cout << root->data << " ";
        display(root->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是一个非常糟糕的构造,因为不清楚它是否转移任何所有权,也不清楚它在内部调用create(data)并使用new创建一个Node。

创建内容如下:

std::unique_ptr<Node> create(int data)
{
    auto node = std::make_unique<Node>();
    node->data = data;
    return std::move(node);
}

insert_ref_to_ptr的功能如下:

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