在 C++ 中复制包含所有元素的对象! (构造函数和赋值,最佳实践?)
Copying objects with all elements in C++! (Constructors and Assignment, best practice?)
我翻遍了 SO,学到了很多关于默认构造函数、复制构造函数、对象赋值、智能指针、shallow/deep 复制以及它们与动态内存分配的关系(例如 This, , That 和 ... ).但是,对于处理复制对象元素(例如向量(或列表))的最佳实践是什么,我仍然不清楚得出什么结论。
我学习了 STL 向量,特别是通过其默认复制构造函数处理此问题,在这种情况下的最佳做法是不要自己管理资源。但似乎我理解错了。
我在提问之前所做的努力:我也能够通过引用传递对象来解决这个问题,但我最终有太多的遵从运算符(即 **)。
对于简单的小对象(例如以下代码中的对象),这里的最佳做法是什么?矢量中的元素未正确复制。 (如果我在这里犯了非常简单的错误,我不会感到惊讶。另外,如果可能的话,最好不要使用 raw/shared/smart 指针)。
#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;
}
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
我想我理解您想要实现的目标,但是如果 objective 正在学习,那么我强烈建议您了解为什么,您期望发生的事情没有发生。在继续寻找 "workaround" 来实现您想要实现的目标之前。
为了更好地理解,编写演示相同行为的简化代码可能会有所帮助。你写的是more-or-less相当于:
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
,保存在a0
中的a1
副本不变。
编辑:
至于如何实现你想实现的。我假设 A
不应该拥有它的 children。您希望它包含对别处保存的 A
的 non-owning 引用。不幸的是,std::vector
不能包含 C++ 引用。 std::vector
可以保存原始指针,但您明确要求不要使用原始指针。
另一种选择是 std::reference_wrapper<A>
,它的行为有点像 C++ 引用,但可以分配,因此可以在 std::vector
中使用。您可以通过提供成员函数来隐藏 std::reference_wrapper
以通过索引访问 child:
#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
基本上只是一个原始指针的包装,由您来确保它指向的 object 仍然存在。
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";
}
注意初始化vector时必须使用&
获取a1
的地址。
我翻遍了 SO,学到了很多关于默认构造函数、复制构造函数、对象赋值、智能指针、shallow/deep 复制以及它们与动态内存分配的关系(例如 This,
我学习了 STL 向量,特别是通过其默认复制构造函数处理此问题,在这种情况下的最佳做法是不要自己管理资源。但似乎我理解错了。
我在提问之前所做的努力:我也能够通过引用传递对象来解决这个问题,但我最终有太多的遵从运算符(即 **)。
对于简单的小对象(例如以下代码中的对象),这里的最佳做法是什么?矢量中的元素未正确复制。 (如果我在这里犯了非常简单的错误,我不会感到惊讶。另外,如果可能的话,最好不要使用 raw/shared/smart 指针)。
#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;
}
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
我想我理解您想要实现的目标,但是如果 objective 正在学习,那么我强烈建议您了解为什么,您期望发生的事情没有发生。在继续寻找 "workaround" 来实现您想要实现的目标之前。
为了更好地理解,编写演示相同行为的简化代码可能会有所帮助。你写的是more-or-less相当于:
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
,保存在a0
中的a1
副本不变。
编辑:
至于如何实现你想实现的。我假设 A
不应该拥有它的 children。您希望它包含对别处保存的 A
的 non-owning 引用。不幸的是,std::vector
不能包含 C++ 引用。 std::vector
可以保存原始指针,但您明确要求不要使用原始指针。
另一种选择是 std::reference_wrapper<A>
,它的行为有点像 C++ 引用,但可以分配,因此可以在 std::vector
中使用。您可以通过提供成员函数来隐藏 std::reference_wrapper
以通过索引访问 child:
#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
基本上只是一个原始指针的包装,由您来确保它指向的 object 仍然存在。
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";
}
注意初始化vector时必须使用&
获取a1
的地址。