深度复制派生类中的指针向量

Deep copying a vector of pointers in derived class

提问人:botetta 提问时间:4/13/2022 更新时间:4/13/2022 访问量:153

问:

我有一个名为 Cipher 的纯虚拟类

class Cipher
{
public:
    //This class doesn't have any data elements
    virtual Cipher* clone() const = 0;
    virtual ~Cipher() { };
    //The class has other functions as well, but they are not relevant to the question
};

Cipher 还有其他一些派生类(例如 CaesarCipher)。问题将是关于 CipherQueue 的,它看起来像这样:

//I've tried to only include the relevant parts here as well
class CipherQueue: public Cipher
{
    std::vector<Cipher*> tarolo;
public:
    void add(Cipher* cipher)
    {tarolo.push_back(cipher);}
    
    CipherQueue(const CipherQueue& _rhs); //?????
    CipherQueue* clone() const;           //?????


    ~CipherQueue()
    {
        for (size_t i = 0; i < tarolo.size(); i++)
        {
            delete tarolo[i];
        }
        //tarolo.clear(); //not sure if this is needed
    }

CipherQueue 有一个名为 tarolo 的向量。它包含指向 Cipher 的派生类的指针。您可以使用 new 运算符或给定类的 clone 函数(已实现)向此向量添加元素:

CipherQueue example;
example.add(new CaesarCipher(3))
CaesarCipher c(6);
example.add(c.clone());
//It is the job of the CipherQueue class to free up the memory afterwards in both cases

现在的问题是:如何在 CipherQueue 中实现复制构造函数和克隆函数,以便在克隆函数中使用复制构造函数,并且克隆函数创建调用它的对象的深度副本? 我已经做了我认为是浅拷贝的东西,这并不好,因为析构函数不能与浅拷贝一起使用。 (或者析构函数也可能是错的吗? 目标是使它能够使您可以执行以下操作:~CipherQueue()

CipherQueue example;
CipherQueue inside; //Let's say that this already has a few elements in it
example.add(inside.clone());
example.add(example.clone()); //This should also work

这是我之前尝试过的,没有使用复制构造函数(我认为这是一个浅层副本,因此它会导致我的程序出现分段错误):

    CipherQueue* clone() const
    {  
        CipherQueue* to_clone = new CipherQueue;
        to_clone->tarolo = this->tarolo;
        return to_clone;
    }
C++ 继承向 克隆 纯虚拟

评论

0赞 Sam Varshavchik 4/13/2022
如果您将显示的代码转换为满足当前代码的最小可重现示例的所有要求的内容,这将有助于增加正确答案的机会。虽然这里的解决方案看起来很简单,但过去有太多次,当时间投入到写答案时,却遇到了“对不起,但由于<X>我认为不相关,因此从未提及,这是行不通的”。请显示当前代码的完整最小可重现示例,没有复制构造函数和有问题的克隆函数。
3赞 François Andrieux 4/13/2022
to_clone->tarolo = this->tarolo;导致两个对象指向相同的对象,最终导致双重删除。使用任何你使用的地方,删除自定义析构函数,编译器将防止你犯这些类型的错误。CipherQueueCipherstd::unique_ptr<Cipher>Cipher*
0赞 Marius Bancila 4/13/2022
您克隆了队列,但未克隆其内容。您刚刚将元素从一个向量复制到另一个向量,但您需要做的是用当前队列元素的克隆填充新队列的向量。tarolo
0赞 paolo 4/13/2022
如果你的类是要多态使用的,你可以考虑抑制它的copy-ctor:isocpp.github.io/CppCoreGuidelines/...Cipher

答:

0赞 botetta 4/13/2022 #1

谢谢 Marius Bancila,你是对的,问题是我只是复制指针,而不是在新向量中创建新对象。我在每个对象上调用了 clone(),现在它运行良好!这是工作克隆功能,以防将来有人偶然发现此线程:

    CipherQueue* clone() const
    {
        CipherQueue* to_clone = new CipherQueue;
        to_clone->tarolo = this->tarolo; //First we copy the pointers
        for (size_t i = 0; i < this->tarolo.size(); i++)
        {
            to_clone->tarolo[i] = tarolo[i]->clone(); //Then we use the clone function on each element to actually create new objects, and not just have copied pointers
        }
        return to_clone;
    }

最后,似乎我根本不需要复制构造函数。您可以在没有它的情况下使克隆功能。