В C++ вызов функции std::список объектов, а не с связанного списка


Это может быть сделано более C++ как с std::list или как-то так Clink класс не нужен?

У меня есть динамический список объектов, и число их может меняться во время выполнения.

Ожидаемые результаты в определенном порядке. В качестве примера 'КБ' перед 'Калифорния':

link-contructed
Ca-contructed
Cb-contructed
Cb-run
Ca-run
Ca-destructed
Cb-destructed
link-destructed

Я хотел бы, чтобы программа была более C++ как с std::list или что-то. Я посмотрел на объект std::forward_list , но не очень представляю, как это должно использоваться. Все примеры я могу найти около std::list<int>. Мой Ctask нужно next в нем и Clink нужно знать, какие объекты используется. Не так универсальна. Вот смешанные C/с++ программа, которая делает ожидается:

/*
vim: ts=4 :
g++ -lstdc++ -o linked linked.cpp && ./linked
*/

#include <iostream>
using namespace std;

class Ctask {
public:
    Ctask *next = NULL;
    Ctask(void) {}
    virtual ~Ctask(void) {}
    virtual void run(void) = 0;
};

/* --------------------------------- */

class Clink {
public:
    Clink(void) {
        cout << "link-contructed" << endl;
    }
    ~Clink(void) {
        Ctask *temp;
        while (temp = head) {
            head = head->next;
            delete temp;
        }
        cout << "link-destructed" << endl;
    }
    void run(void) {
        Ctask *temp = head;
        while (temp) {
            temp->run();
            temp = temp->next;
        }
    }
    void add(Ctask *newnode) {
        if (tail)
            tail->next = newnode;
        else
            head = newnode;
        tail = newnode;
    }
private:
    Ctask *head = NULL;
    Ctask *tail = NULL;
};

/* --------------------------------- */

class Ca: public Ctask {
public:
    Ca(void) {
        cout << "Ca-contructed" << endl;
    }
    ~Ca(void) {
        cout << "Ca-destructed" << endl;
    }
    void run(void) {
        cout << "Ca-run" << endl;
    }
};

class Cb: public Ctask {
public:
    Cb(void) {
        cout << "Cb-contructed" << endl;
    }
    ~Cb(void) {
        cout << "Cb-destructed" << endl;
    }
    void run(void) {
        cout << "Cb-run" << endl;
    }
};

/* --------------------------------- */

int main(void) {
    Clink link;
    link.add((Ctask *)new Ca());
    link.add((Ctask *)new Cb());
    link.run();
    return 0;
}


162
1
задан 17 февраля 2018 в 07:02 Источник Поделиться
Комментарии
2 ответа

Исходя из вашего ответа и комментариев от @user673679, с некоторыми изменениями:


  • Удаление using namespace std.

  • Используя unique_ptr для автоматической обработки объекта выделения и освобождения. Помните, чтобы создать элементы с make_unique.

  • forward_list просто отлично для очереди FIFO.

Обратите внимание, что я не использую диапазона на основе цикла for, потому что я повторяю лишь один раз в списке (запустить функцию и удалить элемент).

#include "ctask.h" // Ctask, Ca and Cb definitions
#include <forward_list>
#include <iterator>
#include <memory>

class TaskQueue {
public:
TaskQueue() :
_tasks(),
_last( _tasks.before_begin() )
{
}

~TaskQueue() = default;

void add( std::unique_ptr<Ctask>&& t ) {
_last = _tasks.insert_after( _last, std::move(t) );
}

void run_all() {
task_list::iterator prev = _tasks.before_begin();
task_list::iterator curr = _tasks.begin();
while( curr != _tasks.end() ) {
(*curr)->run();
curr = _tasks.erase_after(prev);
}
_last = prev;
}

private:
typedef std::forward_list<std::unique_ptr<Ctask>> task_list;
task_list _tasks;
task_list::iterator _last;
};

int main(void) {
TaskQueue queue;
queue.add(std::make_unique<Ca>());
queue.add(std::make_unique<Cb>());
queue.run_all();
return 0;
}

Edit: я понял, что вы можете сделать run_all более читабельна, поскольку вы, по сути, сняв все элементы из очереди, так что в то время как цикл на самом деле не зависят от _last значение. Упрощенная функция будет:

   void TaskQueue::run_all() {
while( !_tasks.empty() ) {
_tasks.front()->run();
_tasks.pop_front();
}
_last = _tasks.before_begin();
}

3
ответ дан 20 февраля 2018 в 01:02 Источник Поделиться

Посмотрев на большое std::list примеры я придумал такое решение:

#include <iostream>
#include <list>
#include <iterator>
#include <memory>
using namespace std;

class Ctask {
public:
Ctask(void) {}
virtual ~Ctask(void) {}
virtual void run(void) = 0;
};

/* --------------------------------- */

class Ca: public Ctask {
public:
Ca(void) {
cout << "Ca-contructed" << endl;
}
~Ca(void) {
cout << "Ca-destructed" << endl;
}
void run(void) {
cout << "Ca-run" << endl;
}
};

class Cb: public Ctask {
public:
Cb(void) {
cout << "Cb-contructed" << endl;
}
~Cb(void) {
cout << "Cb-destructed" << endl;
}
void run(void) {
cout << "Cb-run" << endl;
}
};

/* --------------------------------- */

int main(void) {
std::list<std::unique_ptr<Ctask>> taskList;
taskList.push_back(std::make_unique<Ca>());
taskList.push_back(std::make_unique<Cb>());
for (auto& t : taskList)
t->run();
return 0;
}


  1. Что бы быть более точным вопрос к задаче?

  2. Это правильно & ООН-уродливый способ сделать это?

  3. Может (*tl)->run() быть написана лучше?

  4. Может delete (*tl) быть обработаны по-разному, и следует избегать прямого звонка delete?

1
ответ дан 20 февраля 2018 в 08:02 Источник Поделиться