Как я могу создать список динамических объектов в C++

У меня есть эта простая программа на C++

#include <iostream>
#include <string>
#include <list>
using namespace std;

class test {
    private:
        string _name;
        list<test*> _list;
    public:
        test(const string& S): _name(S) { this->_list.clear(); }

        const string& to_string() {
            string*sp = new string("[");
            *sp += this->_name;
            for(test*tp: this->_list) {
                *sp += ",";
                *sp += tp->to_string();
            }
            *sp += "]";
            return *sp;
        }

        test& add(const string& S) {
            test*tp = new test(S);
            this->_list.push_back(tp);
            return *tp;
        }
};

int main() {
    test x("one");
    x.add("two");
    test y = x.add("three");
    y.add("four");
    cout << y.to_string() << '\n';
    cout << x.to_string() << '\n';
}

Идея состоит в том, чтобы создать список вложенных списков. y должен быть элементом xОднако, когда я изменяю y, затем x не изменяется

Желаемый результат:

[three,[four]]
[one,[two],[three,[four]]]

но я получаю

[three,[four]]
[one,[two],[three]]

Я, вероятно, могу решить эту проблему, возвращая указатель в test::add и модифицирование main:

int main() {
    test x("one");
    x.add("two");
    test*p = x.add("three");
    p->add("four");
    cout << y->to_string() << '\n';
    cout << x.to_string() << '\n';
}

Тем не мение. Есть ли способ использовать y как тип test скорее, чем p как тип test*?

3 ответа

Вы создали копию "три" и добавили "четыре" к ней.

test y = x.add("three");

Вы можете сделать как:

test& y = x.add("three");

Кстати, ваш код создает утечки памяти. Напишите виртуальный деструктор.

Да, вы можете просто сделать y test& сохранить отношения с x:

Живой пример

Вы, кажется, используете много объектов, динамически размещаемых в куче. Рассмотрите возможность использования умных указателей (например, std::shared_ptr) вместо необработанных владеющих указателей, для правильной очистки и предотвращения утечек.

Я не потратил много времени на это, но взял ваш исходный код и заменил некоторые необработанные указатели на умные указатели (и std::list с std::vector; если ты не хочешь list для его свойств недействительности итератора, std::vector как правило, лучший вариант), я получил этот код, который, кажется, работает ( пример в реальном времени):

Выход:

[three,[four]]
[one,[two],[three,[four]]]

Источник:

#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace std;

class Test {
private:
    string _name;
    vector<shared_ptr<Test>> _list;
public:
    explicit Test(const string& S) : _name(S) { }

    string to_string() const {
        string s("[");
        s += _name;

        for (auto const& p : _list) {
            s += ",";
            s += p->to_string();
        }

        s += "]";
        return s;
    }

    shared_ptr<Test> add(const string& S) {
        auto p = make_shared<Test>(S);
        _list.push_back(p);
        return p;
    }
};

int main() {
    auto x = make_shared<Test>("one");
    x->add("two");
    auto y = x->add("three");
    y->add("four");

    cout << y->to_string() << '\n';
    cout << x->to_string() << '\n';
}

В качестве альтернативы, если это имеет смысл для вашего конкретного дизайна, вы также можете рассмотреть возможность возврата ссылок (T&) к вашим объектам из test::add вместо (умных) указателей и используйте unique_ptr (вместо shared_ptr) с _list элемент векторных данных. Это своего рода альтернативная версия ( вживую):

#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace std;

class Test {
private:
    string _name;
    vector<unique_ptr<Test>> _list;
public:
    explicit Test(const string& S) : _name(S) { }

    string to_string() const {
        string s("[");
        s += _name;

        for (auto const& p : _list) {
            s += ",";
            s += p->to_string();
        }

        s += "]";
        return s;
    }

    Test& add(const string& S) {
        _list.push_back(make_unique<Test>(S));
        return *(_list.back());
    }
};

int main() {
    Test x("one");
    x.add("two");
    Test& y = x.add("three");
    y.add("four");

    cout << y.to_string() << '\n';
    cout << x.to_string() << '\n';
}
Другие вопросы по тегам