Как я могу создать список динамических объектов в 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';
}