oop — Копирование объектов со всеми элементами в C ++! (Конструкторы и назначение, лучшая практика?)

Я порылся в SO и узнал много нового о конструкторах по умолчанию, конструкторах копирования, назначении объектов, умных указателях, мелком / глубоком копировании и их взаимосвязях с динамическим выделением памяти (например, это, это, Тот а также …). Тем не менее, я все еще не уверен, что могу сделать вывод о том, что лучше всего делать с копированием таких объектов, как векторы (или списки).

Я узнал, что вектор STL, в частности, обрабатывает его с помощью конструктора копирования по умолчанию, и в этом случае рекомендуется не управлять ресурсами самостоятельно. Но, похоже, я понимаю, что-то не так.

Мои усилия, прежде чем спросить: я также смог решить эту проблему, передав объекты по ссылке, но у меня закончилось слишком много операторов связи (т.е. **).

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

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

class A{
public:
int id;
A(int id_):id(id_){}
vector<A> childs;
};

int main()
{
A a0(0), a1(1);

a0.childs={a1}; //node0.childs.push_back(node1);
a1.childs={a0}; //node1.childs.push_back(node0);

cout << a0.childs.size() << endl; // 1
cout << a1.childs.size() << endl; // 1
cout << a0.childs[0].childs.size() << endl; // expecting 1 but 0
//Probably since they're not pointing to the same address of memory
//I was hoping vector handle this by itself (was told best practice in this case is to not manage resources yourself)

return 0;
}

1

Решение

Я думаю, что понимаю, чего вы пытаетесь достичь, но если цель состоит в обучении, то я настоятельно рекомендую вам понять, почему то, чего вы ожидаете, не происходит. Прежде чем перейти к поиску «обходного пути» для достижения того, чего вы пытаетесь достичь.

Чтобы лучше понять, это может помочь написать упрощенный код, демонстрирующий то же поведение. То, что вы написали, более или менее эквивалентно:

struct A {
int childCount = 0;
};

int main() {
A a1;
std::vector<A> vecA{a1};
a1.childCount = 1;
std::cout << vecA[0].childCount<< "\n"; // What do you expect here?
}

что эквивалентно:

A a1;
A copyOfA1 = a1;
a1.childCount= 1;
std::cout << copyOfA1.childCount << "\n"; // What do you expect here?

что эквивалентно:

int a1 = 0;
int copyOfA1 = a1;
a1 = 1;
std::cout << copyOfA1 << "\n";  // What about here?

a0 держит отдельный копия из a1 не ссылка на a1 так что если вы внесете изменения в оригинал a1Копия a1 проводится в a0 не меняется.

РЕДАКТИРОВАТЬ:
Что касается того, как добиться того, чего вы хотите достичь. Я предполагаю что A не должен владеть своими детьми. Вы хотите, чтобы он содержал несобственные ссылки на Aс, которые проводятся в другом месте. К сожалению, std::vector не может содержать ссылку на C ++. std::vector может содержать необработанный указатель, но вы специально просили не использовать необработанные указатели.

Альтернатива, это std::reference_wrapper<A> который ведет себя немного как ссылка на C ++, но присваивается так, чтобы его можно было использовать в std::vector, Вы могли бы скрыть std::reference_wrapper предоставляя функцию-член для получения доступа к дочернему элементу по индексу:

#include <iostream>
#include <vector>
#include <functional>

struct A {
int id;
A(int id_):id(id_){}
std::vector<std::reference_wrapper<A>> childs;
A& at(size_t index) { return childs[index]; }
};

int main()
{
A a0(0), a1(1);

a0.childs={a1};
a1.childs={a0};

std::cout << a0.childs.size() << "\n";
std::cout << a1.childs.size() << "\n";
std::cout << a0.at(0).childs.size() << "\n";
}

Живая демо.

Но чтобы быть ясно, std::reference_wrapper это просто оболочка необработанного указателя, вы должны убедиться, что объект, на который он указывает, все еще жив.

Edit2: По запросу, вот версия, которая использует вектор необработанных указателей:

#include <iostream>
#include <vector>

struct A {
int id;
A(int id_):id(id_){}
std::vector<A*> childs;
A& at(size_t index) { return *childs[index]; }
};

int main()
{
A a0(0), a1(1);

a0.childs={&a1};
a1.childs={&a0};

std::cout << a0.childs.size() << "\n";
std::cout << a1.childs.size() << "\n";
std::cout << a0.at(0).childs.size() << "\n";
}

Живая демо.

Обратите внимание, что вы должны взять адрес a1 с помощью & при инициализации вектора.

0

Другие решения

a0.childs={a1}; //a1.childs is empty here, so a0.childs will be empty too
a1.childs={a0}; //a0.childs contains one element here and so will a1.childs

Так

 cout << a0.childs[0].childs.size() << endl; // This size will be 0

Но

cout << a1.childs[0].childs.size() << endl; // This will contain one element and the output shows the same.

Выход:

a.exe
a0.childs.size():1
a1.childs.size():1
a0.childs[0].childs.size():0
a1.childs[0].childs.size():1
0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector