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

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

我需要在我的项目中进行深层复制,现在我 memcpysrcObj 转换为 destObj 然后 如果 destObj 拥有指针成员,我只需创建所有 obj 并递归执行此方法

这是伪造的:

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] 也会发生变化,它们都指向一个地址,我不知道为什么会这样。

感谢任何帮助。

memcpy()绝对错误,需要删除。它正在破坏你的 A 对象的数据成员。它可能objB 成员有效,但绝对不适用于 vecInt 成员。

但是,即使删除了 thae memcpy(),您仍然会有 未定义的行为,因为您试图分配给 vector 未定义的元素还存在。对于 deep-copy 指针向量,您别无选择,只能一次克隆每个动态 B 对象并将其添加到新的 vector.

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

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

根据 Rule of 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;
    }
};

也就是说,考虑使用 std::vector<std::unique_ptr<B>> 而不是 std::vector<B*>。这将消除对显式析构函数的需要。如果可以避免,请不要在现代 C++ 中使用 new/delete

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);
    }
};