在复制构造函数中做指针的深度复制向量是否更改了两个向量成员?

doing deep copy vector of pointers in copy constructor got both vector member changed?

提问人:liiight 提问时间:10/29/2020 更新时间:10/29/2020 访问量:296

问:

我需要在我的项目中进行深度复制,现在我进入了 如果拥有指针成员,我只需创建所有 obj 并以递归方式执行此方法memcpysrcObjdestObjdestObj

这是伪:

class B
{
public:
    B(int id_) : id(id_) {};
    int id = 0;
};

class A
{
public:
    vector<B*> vecInt;
    B objB = 111;
    A()
    {
        vecInt.push_back(new B(1));
        vecInt.push_back(new B(2));
        vecInt.push_back(new B(3));
    }
    A(const A& rhs)
    {
        memcpy(this, &rhs, sizeof(A));
        for (auto i = 0; i < rhs.vecInt.size(); i++)
        {
            auto ptrTmp = new B(rhs.vecInt[i]->id);
            cout << "00000000000 " << rhs.vecInt[i] << endl;;
            this->vecInt[i] = ptrTmp;
            cout << "11111111111 " << ptrTmp << endl;;
            cout << "22222222222 " << rhs.vecInt[i] << endl;;
        }
    }
};

这就是问题所在,每次我在循环中分配时,更改也会发生,并且它们都指向一个地址,我不知道为什么会发生这种情况。this->vecInt[i]rhs.vecInt[i]

感谢任何帮助。

C++ 矢量 复制构造函数 deep-copy

评论

1赞 molbdnilo 10/29/2020
导致未定义的行为。在C++中有效的情况很少。memcpymemcpy

答:

1赞 Remy Lebeau 10/29/2020 #1

这是绝对错误的,需要删除。它正在损坏对象的数据成员。它可能对会员有用,但绝对对会员无效。memcpy()AobjBvecInt

但是,即使删除了 thae,在尝试分配给尚不存在的元素时,您仍然会有未定义的行为。若要深度复制指针向量,您别无选择,只能一次克隆一个动态对象并将其添加到新的 .memcpy()vectorBvector

实现复制构造函数的正确方法应更像这样:

    A(const A& rhs) : objB(rhs.objB)
    {
        vecInt.reserve(rhs.vecInt.size());
        for (auto *elem : rhs.vecInt)
        {
            vecInt.push_back(new B(*elem));
        }
    }

您还需要根据 3/5/0 规则添加析构函数、移动构造函数、复制赋值运算符和移动赋值运算符:

class A
{
public:
    vector<B*> vecInt;
    B objB = 111;

    A()
    {
        vecInt.push_back(new B(1));
        vecInt.push_back(new B(2));
        vecInt.push_back(new B(3));
    }

    A(const A& rhs) : objB(rhs.objB)
    {
        vecInt.reserve(rhs.vecInt.size());
        for (auto *elem : rhs.vecInt)
        {
            vecInt.push_back(new B(*elem));
        }
    }

    A(A&& rhs) : vecInt(move(rhs.vecInt)), objB(move(rhs.objB)) {}

    ~A()
    {
        for(auto *elem : vecInt)
            delete elem;
    }

    A& operator=(A rhs)
    {
        vecInt.swap(rhs.vecInt);
        objB.id = rhs.objB.id;
        return *this;
    }
};

话虽如此,请考虑使用 代替 .这将消除对显式析构函数的需求。如果可以避免,请不要在现代 C++ 中使用 /。std::vector<std::unique_ptr<B>>std::vector<B*>newdelete

class A
{
public:
    vector<unique_ptr<B>> vecInt;
    B objB = 111;

    A()
    {
        vecInt.push_back(make_unique<B>(1));
        vecInt.push_back(make_unique<B>(2));
        vecInt.push_back(make_unique<B>(3));
    }

    A(const A& rhs) : objB(rhs.objB)
    {
        vecInt.reserve(rhs.vecInt.size());
        for (auto &elem : rhs.vecInt)
        {
            vecInt.push_back(make_unique<B>(*elem));
        }
    }

    A(A&& rhs) : vecInt(move(rhs.vecInt)), objB(move(rhs.objB)) {}

    ~A() = default;

    A& operator=(A rhs)
    {
        vecInt.swap(rhs.vecInt);
        objB.id = rhs.objB.id;
        return *this;
    }
};

更好的是,改用,让编译器为你处理其他所有事情:std::vector<B>

class A
{
public:
    vector<B> vecInt;
    B objB = 111;

    A()
    {
        vecInt.emplace_back(1);
        vecInt.emplace_back(2);
        vecInt.emplace_back(3);
    }
};

评论

0赞 liiight 10/29/2020
感谢您的帮助,我还没有注意到它是如此恶毒,它现在可以工作了,但是由于我需要为某些对象使用太多指针,我想我只是无法实现最后一个。但是既然现在不能使用,那么我应该一个接一个地分配所有数据成员,我只是觉得这真的很难维护,还是有其他方法可以处理这么多数据成员的情况?memcpymemcpy