Простая реализация универсального стека

Я довольно новичок в программировании на C ++. Чтобы помочь, я пишу свои собственные структуры данных для практики. Мне бы понравилось, чтобы об этом судили, как если бы оно было написано профессионалом, и получали честные отзывы. У меня уже есть несколько проблем.

  1. Правильно ли я управляю памятью? Я не верю, что у меня есть утечки. Много советов, которые я получаю при использовании указателей, - это использование умных указателей, но необработанные указатели хороши, когда класс инкапсулирует все указатели правильно?

  2. Я недоволен, моя перегрузка оператора << должна вызвать peekAll внутри класса. Я чувствую, что поступаю неправильно. Помимо этого я должен перегружать любые другие операторы? Я не чувствовал, что арифметические операторы имеют большой смысл.

#include <ostream>

template <typename T>
class BBStack {
public:
BBStack(T type) {
    head = new Node(type);
}

virtual ~ BBStack() {
    Node* temp = head;
    while (head != nullptr) {
        temp = head->next;
        delete head;
        head = temp;
    }
    delete temp;
}

void push(T type) {
    Node *newNode = new Node(type, head);
    head = newNode;
}

T peek() const {
    return head->data;
}

T pop() {
    if (head == nullptr) {
        std::cout<<"Error stack is empty"<<std::endl;
        return NULL;
    } else {
        Node *temp = head;
        T result = temp->data;
        head = head->next;
        delete temp;
        return result;
    }
}

std::ostream& peekAll(std::ostream& out) const {
    if (head == nullptr) return out << "Stack is empty";
    Node* temp = head;

    while (temp != nullptr) {
        out << temp->data << " ";
        temp = temp->next;
    }

    delete temp;
    return out;
}

private:
    struct Node {
        Node(T type, Node* _next = nullptr) : data(type), next(_next) {}
        Node(Node* node) : data (node->data), next (node->next) {}

        T data;
        Node* next;
    };
    Node* head;

};

template <typename T>
std::ostream& operator<< (std::ostream& out, const BBStack<T>& stack) {
    return stack.peekAll(out);
}
8 голосов | спросил Brian 21 stEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 21 Sep 2015 05:29:00 +0300 2015, 05:29:00

1 ответ


2

В профессиональном контексте советом будет: «удалите весь этот код и используйте std::stack<T> ».

Но предположим, что std::stack<T> не существует в стандартной библиотеке или вы хотите написать еще одну контейнероподобную сущность еще изобрел. Профессиональный совет будет: «стараться использовать как можно больше существующего кода». Например. реализовать std::stack<T> в терминах существующего контейнера, такого как std::list<T>, std::vector<T> или std::deque<T>.

Это автоматически устранит все проблемы управления памятью. В профессиональном коде, если только тщательно не задокументировано, почему это было бы абсолютно необходимо, я бы не ожидал увидеть необработанные new или delete, и вместо этого можно увидеть либо unique_ptr и make_unique или контейнеры управления памятью, такие как std::vector или std::string

Кстати, именно так стандартная библиотека реализует std::stack<T>, потому что это контейнерный адаптер , а не контейнер. Точный шаблон класса:

template<
    class T,
    class Container = std::deque<T>
> class stack;

Это хорошее упражнение для реализации функций-членов стека emplace(), push() и pop() в терминах emplace_back(), push_back() и pop_back() основного контейнера. Это все еще не совсем тривиально, потому что вы должны быть осторожны с идеальной переадресацией и семантикой перемещения. Связанная документация должна предоставить вам достаточно советов, чтобы справиться с этим.

Обратите внимание, что std::stack не предоставляет operator<< и не предоставляет итераторов для просмотра его элементов. Однако у него есть защищенный элемент c, который предоставляет доступ к базовому контейнеру. Затем вы можете написать адаптер, который использует итераторы контейнера для отображения базовых элементов:

#include <iostream>
#include <iterator>
#include <stack>
#include <vector>

template<class Adaptor>
struct container_view
:
    public Adaptor
{
    container_view() = default;
    using Adaptor::Adaptor;
    auto begin() const { return this->c.begin(); }
    auto end() const { return this->c.end(); }
};

int main()
{
    std::vector<int> v = { 1, 2, 3, 4 };
    container_view<std::stack<int, std::vector<int>>> const c(v);
    std::copy(begin(c), end(c), std::ostream_iterator<int>(std::cout, ","));
}

Живой пример .

Обратите внимание, что его адаптер также работает для двух других контейнерных адаптеров стандартной библиотеки: std::priority_queue и std::queue

ответил TemplateRex 21 stEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 21 Sep 2015 09:32:48 +0300 2015, 09:32:48

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132