【问题标题】:Swapping an object within itself交换自身内部的对象
【发布时间】:2012-08-21 12:27:26
【问题描述】:

我正在尝试在其内部交换一个对象。它可以工作,但是当我添加一个析构函数时,它会给我一个双重免费错误。有没有办法防止这种情况?我说的方法是void swap(SimpleArray &object)

(对不起,如果您在我的帖子中有错误信息之前阅读了此内容...)

#include "TestType.h"
class SimpleArray {

    private: 
        TestType* pArray;
        //TestType* temp;
    public:
        SimpleArray(TestType *array)
        {
            this->pArray = array;
        }
        ~SimpleArray() { delete[] pArray; }
        SimpleArray() { pArray = 0;}
        SimpleArray(const SimpleArray& arg){ pArray = arg.pArray; }
        ~SimpleArray() { delete[] pArray; }
        TestType * get() const{ return pArray; }
        bool isNonNull() const { return pArray != 0; }
        //TestType* pArray;
        void reset(TestType*& p) {this->pArray = p; }
        void reset() { pArray = 0; }

        void swap(SimpleArray &object) { SimpleArray temp; temp = object; object = *this; *this = temp;}
        TestType * release() { pArray = 0; return pArray; }
        TestType& getReference(int a) { return *pArray; }


};

这可行,但是一旦我添加了析构函数,它就会给我一个“双重释放或损坏错误”。我该如何解决这个问题?这是 main 中出现问题的函数。

bool testGetReleaseSwap() {
    SimpleArray array1;
    if (array1.get() != 0)
        return false;

    TestType* directArray1 = new TestType[100];
    array1.reset(directArray1);
    if (array1.get() != directArray1)
        return false;

    TestType* directArray2 = new TestType[50];
    SimpleArray array2(directArray2);

    array1.swap(array2);
    if (array1.get() != directArray2 || array2.get() != directArray1)
        return false;

    array2.swap(array1);
    if (array1.get() != directArray1 || array2.get() != directArray2)
        return false;

    array1.swap(array1);
    if (array1.get() != directArray1)
        return false;

    if (array1.release() != directArray1 || array2.release() != directArray2)
        return false;

    if (array1.get() != 0 || array2.get() != 0)
        return false;

    delete[] directArray1;
    delete[] directArray2;

    return true;
}

【问题讨论】:

  • What is The Rule of Three? 的可能重复您缺少复制赋值运算符,并且您的复制构造函数执行浅拷贝,使两个对象拥有相同的数组。
  • 感谢您的帮助。修复了问题。

标签: c++ oop destructor delete-operator double-free


【解决方案1】:

这里的简单方法是在您的 swap 方法的末尾调用 temp.release() 以防止重复删除。

不过,潜在的问题要深得多。在 C++ 中,始终保持对谁拥有某物的严格语义至关重要,例如需要删除的内存区域。

一种常见的模式是分配某物的对象也负责清理而不是其他人。这很适合SimpleArray,但是复制构造函数会破坏它,因为它会增加所有者的数量!

要实现共享数据语义,您必须投入更多工作(引用计数等),或者您必须禁止数组复制并将复制构造函数设为私有。

在不复制对象的情况下修复 swap 以工作的干净方法是:

 void swap(SimpleArray &object) { 
    TestType* temp = object.pArray;
    object.pArray = this->pArray;
    this->pArray = temp;
 }

std::swap(object.pArray, pArray); 也可以)

因为交换数组的内存区域非常适合单所有者模式,所以这里的错误只是使用了完整的对象副本。

您应该阅读 C++ 中的资源管理和所有权语义。除非您完全知道谁拥有什么,否则您的代码总是容易出错。

【讨论】:

  • 很抱歉,它们工作正常,但仍然有一堆内存。部分任务是确保没有内存泄漏。
  • 谢谢。看了三个的规则后,我在我的课堂上做了一个 operator= 方法。之前交换没有按预期工作,但现在它工作得很好。
【解决方案2】:

在我看来,您正在尝试实现一个具有浅复制语义的类(并且可能是写时复制)。要成功地做到这一点,您需要跟踪有多少其他共享数据的所有者仍然存在并且需要销毁拥有的对象,当该计数达到零时。您可以为此使用std::shared_ptr,也可以自己实现引用计数。

至于该特定示例中的真正问题,请查看您的复制构造函数在做什么。它不是复制,而是简单地对其参数已经拥有的对象进行另一个引用(具体的指针)。这本身就足以获得双重免费,而您的 swap 测试用例只是暴露了这个问题。

【讨论】:

  • 那么如何修复复制构造函数?
  • @user1447974 如果您不打算实际实现浅拷贝或写时复制,则 copy ctor 需要实际 copy 它的参数数组。
  • 所以我想做浅拷贝?我猜我现在正在做的实际上是一个深拷贝?
  • @user1447974 不,您正在执行浅拷贝。正如我所说:您只是将副本的指针设置为与您正在复制的对象相同的对象。你想做的是一个深拷贝。
  • 谢谢。只是误会了。搞定了。
猜你喜欢
  • 1970-01-01
  • 2018-11-12
  • 2014-01-30
  • 1970-01-01
  • 2019-11-10
  • 1970-01-01
  • 1970-01-01
  • 2022-11-03
相关资源
最近更新 更多