1

我翻遍了 SO 并学到了很多关于默认构造函数、复制构造函数、对象分配、智能指针、浅/深复制以及它们与动态内存分配的关系(例如ThisThisThat和 ...)。但是,对于最佳实践是处理复制对象元素(例如向量(或列表))的结论,我仍然很模糊。

我特别学习了 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;
}
4

2 回答 2

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
于 2018-10-22T05:02:17.560 回答
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持有非参考的单独副本,因此如果您对原件进行更改,则持有的副本不会更改。a1a1a1a1a0

编辑:至于如何实现您想要实现的目标。我假设不A应该拥有它的孩子。A您希望它包含对在别处保存的 s 的非拥有引用。不幸的是, astd::vector不能保存 C++ 引用。可以保存原始指针,std::vector但您特别要求不要使用原始指针。

另一种选择是 a 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使用的地址。&

于 2018-10-22T08:48:18.533 回答