我在SO上翻遍,学到了很多有关默认构造函数,副本构造函数,对象分配,智能指针,浅/深副本以及它们与动态内存分配的关系(例如This,This,{ {3}}和...)。但是,我对得出最佳做法是处理复制对象元素(例如矢量(或列表))的最佳实践仍不满意。
我了解到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;
}
答案 0 :(得分: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
答案 1 :(得分:0)
我想我理解您正在努力实现的目标,但是如果目标是学习,那么我强烈建议您理解为什么没有实现预期的目标。在继续寻找“解决方法”以实现您要达到的目标之前。
为了更好地理解,编写演示相同行为的简化代码可能会有所帮助。您写的内容大致相当于:
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
来获取&
的地址。