【问题标题】:doing deep copy vector of pointers in copy constructor got both vector member changed?在复制构造函数中做指针的深度复制向量让两个向量成员都改变了?
【发布时间】:2021-02-11 15:51:55
【问题描述】:

我需要在我的项目中进行深层复制,现在我将 memcpy srcObj 转换为 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-&gt;vecInt[i] 时,rhs.vecInt[i] 也会发生变化,它们都指向一个地址,我不知道为什么会这样。

感谢任何帮助。

【问题讨论】:

  • memcpy 导致未定义的行为。 memcpy 在 C++ 中有效的情况很少。

标签: c++ vector copy copy-constructor deep-copy


【解决方案1】:

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

但是,即使删除了 memcpy(),当您尝试分配尚不存在的 vector 元素时,您仍然会有未定义的行为。要深度复制指针向量,您别无选择,只能一次克隆每个动态 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&lt;std::unique_ptr&lt;B&gt;&gt; 而不是std::vector&lt;B*&gt;。这将消除对显式析构函数的需要。如果可以避免,请不要在现代 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&lt;B&gt;,让编译器为您处理所有其他事情:

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

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

【讨论】:

  • 感谢您的帮助,我注意到memcpy 是如此的恶毒并且它现在可以工作了,但是由于我需要为某些对象使用很多指针,我想我只是无法实现最后一个。但是既然现在memcpy不能用了,是不是应该我应该一个一个地分配所有的数据成员,我只是觉得这真的很难维护,或者有其他方法来处理这种情况吗?许多数据成员?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-17
  • 1970-01-01
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多