用C ++复制具有所有元素的对象! (构造函数和作业,最佳实践?)

时间:2018-10-22 04:50:15

标签: c++ oop vector copy-constructor default-copy-constructor

我在SO上翻遍,学到了很多有关默认构造函数,副本构造函数,对象分配,智能指针,浅/深副本以及它们与动态内存分配的关系(例如ThisThis,{ {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;
}

2 个答案:

答案 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";
}

Live demo

但是要清楚一点,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";
}

Live demo

请注意,初始化向量时,必须使用a1来获取&的地址。