Должен ли я избегать ссылки на указатель в современном C ++ или это нормально в этом особом случае - PullRequest
0 голосов
/ 03 февраля 2019

Я знаю, что необработанных указателей (или, точнее, new и delete) в современном C ++ следует избегать, если это действительно не нужно.Я считаю, что когда дело доходит до реализации графа, указатели довольно полезны.Я был бы рад услышать комментарии по этому поводу, хотя.

Я играю с деревьями бинарного поиска и пишу insert функций.Я реализовал с помощью двух разных, но похожих методов, один с использованием указателя, а другой с использованием ссылки на указатель.Ясно, что я хотел бы изменить сам указатель (ref на ptr).Хотите знать, если какой-либо из них имеет преимущества или не должен использоваться и должен быть написан с использованием константной ссылки или умного указателя (современный способ).

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 голосов
/ 03 февраля 2019

that pointers in modern C++ must be avoided unless really needed это неправильно.

new и delete следует избегать, и вместо этого следует использовать уникальные и общие указатели.

Но вы все равно будете передавать объект по ссылке или необработанному указателю, если вы не перенесете владение.

У вас 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) внутри, которые создают Node, используя new.

Создание будет выглядеть примерно так:

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);
}
0 голосов
/ 03 февраля 2019

Я знаю, что указателей в современном C ++ следует избегать, если в этом нет особой необходимости.

Это не так.Вероятно, вы слышали, что вам следует избегать необработанных (голых) указателей, если ваши требования соответствуют стандартизированному шаблону / решению, например unique_ptr.

. Я бы хотел изменить сам указатель (см.к птр).Хотите знать, если какой-либо из них имеет преимущества или не должен использоваться, и должен быть написан с использованием константной ссылки (современный способ).

Если вы хотите иметь выходные параметры, у вас есть несколько способов сделать это:

  • Возвращаемое значение.
  • Ссылка на значение (в качестве параметра).
  • Указатель на значение (в качестве параметра).
  • Несколько возвращаемых значенийв struct, std::tuple или с использованием структурированных привязок.
  • Переменная-член (только для функций-членов в классах).
  • Глобальная переменная.

Тамэто не единственный лучший способ для всех случаев.Какой из них вы используете, зависит от вас и от того, как вы собираетесь использовать эту функцию.В некоторых случаях это также зависит от рекомендаций по стилю кодирования проектов (например, в случае ссылки или указателя).Например:

  • Некоторые люди предпочитают использовать возвращаемое значение, если имеется только один выходной параметр.
  • Некоторые библиотеки предпочитают использовать возвращаемые значения исключительно для кодов ошибок.
  • В некоторых рекомендациях по стилю кодирования избегаются ссылки, потому что они хотят явно видеть в вызывающей стороне, что вы передаете адрес (например, f(a) против f(&a)).
  • В функциях-членах вы обычно используете членапеременные.
  • Почти во всех случаях вам следует избегать глобальных переменных для этой цели.

должны быть записаны с использованием константной ссылки (современный способ).

Кстати, обратите внимание, что вы не написали ссылку const, просто ссылку на Note *.И это не «современный C ++»: ссылки были частью первого стандарта C ++.

...