用`new`分配的`int *`的`delete []`给出了malloc错误

时间:2016-06-18 01:46:54

标签: c++

根据我对C ++约定的理解,我有:

class BlockRepresentation : public FPRepresentation
{
    private:
        class Block
        {
            public:
                int id;
                int fpDimensions;
                int* position;        // pointers in question
                int* blockDimensions; // pointers in question

                ~Block();
        };
        std::vector<Block> all_blocks;

    public:
        BlockRepresentation( int count, int dimensions, int volumn[] );
        void AddBlock( int id, int position[], int dimensions[] );
        std::string ToGPL();
};

AddBlock中创建新块:

void BlockRepresentation::AddBlock( int id, int position[], 
        int dimensions[] )
{
    Block newBlock;

    newBlock.id = id;
    newBlock.fpDimensions = fpDimensions;
    newBlock.position = new int[fpDimensions];        // pointers in question
    newBlock.blockDimensions = new int[fpDimensions]; // pointers in question

    for (int i = 0; i < fpDimensions; ++i)
    {
        newBlock.position[i] = position[i];
        newBlock.blockDimensions[i] = dimensions[i];
    }

    all_blocks.push_back( newBlock );
}

所以我有以下析构函数:

BlockRepresentation::Block::~Block()
{
    delete[] position;
    delete[] blockDimensions;
}

然后我得到:

rep_tests(11039,0x7fff71390000) malloc: *** error for object 0x7fe4fad00240: pointer being freed was not allocated

为什么我不能delete[]这里的2个指针?

2 个答案:

答案 0 :(得分:1)

正如评论中指出的那样,你违反了三条规则,违规行为非常明显:

{
    Block newBlock;

    // snip

    all_blocks.push_back( newBlock );
}

当此函数返回时,newBlock对象超出范围,其析构函数将删除所有new ed数组。

但你push_back()编辑了这个对象。这将对象的副本构造到向量中。因为Block没有定义复制构造函数,所以默认的复制构造函数只是复制了new ed数组的所有指针。

如果你以某种方式设法避免取消引用不再有效的指针,或者你在那段经历中幸存下来,那么你还没有进入森林。这是因为,当向量被破坏并且其Block被破坏时,它们的析构函数将再一次尝试delete相同的new ed数组delete d之前一次。

即时崩溃。

答案 1 :(得分:1)

您的Block析构函数没有任何问题。它正在完成它的工作,即释放两个int *成员变量所指向的内存。问题是析构函数被多次调用相同的指针值,这导致双重自由错误。

导致此问题的实体是std::vector<Block>,因为std::vector将复制您的Block对象,而您的Block对象无法安全复制。

由于Block的成员变量是positionblockDimensions,因此缓解此问题的最简单方法是使用std::vector<int>而不是{{1 },如this sample program所示。

但是,如果您真的想使用int *,则需要实现用户定义的复制构造函数。此外,用户定义的赋值运算符将补充复制构造函数。这就是所谓的Rule of Three

int *

查看实时样本here

查看我们必须跳过的所有箍,以便 #include <algorithm> //... class Block { public: int id; int fpDimensions; int *position; int *blockDimensions; Block() : position(nullptr), blockDimensions(nullptr), id(0), fpDimensions(0) {} ~Block() { delete [] position; delete [] blockDimensions; } Block(const Block& rhs) : id(rhs.id), fpDimensions(rhs.fpDimensions), position(new int[rhs.fpDimensions]), blockDimensions(new int[rhs.fpDimensions]) { std::copy(rhs.position, rhs.position + fpDimensions, position); std::copy(rhs.blockDimensions, rhs.blockDimensions + fpDimensions, blockDimensions); } Block& operator=(const Block& rhs) { Block temp(rhs); std::swap(temp.position, position); std::swap(temp.blockDimensions, blockDimensions); std::swap(temp.id, id); std::swap(temp.fpDimensions, fpDimensions); return *this; } }; 类在Block内使用时能够正常运行,而不是简单地使用std::vector