首页 > 解决方案 > 我的自定义向量有一个运行时错误调试断言失败:_CrtIsValidHeapPointer(block)

问题描述

我的向量类的一部分

class CVector
{
    friend ostream &operator<<(ostream& output, const CVector& vec);

public:

    CVector()
    {
        sPtr = new char[10];
        size = 0;
        capacity = 10;
    }

    CVector(const CVector &vec)
    {
        size = vec.size;
        capacity = vec.capacity;
        sPtr = new char[size];
        cout << "copy constructor" << endl;
        for (size_t i = 0; i < size; i++)
        {
            sPtr[i] = vec.sPtr[i];   
        }
        
    }

主功能

CVector veca;
    cout << veca.getCapacity() << endl;
    cout << veca.getSize() << endl;
    veca.push_back('H');
    veca.push_back('e');
    veca.push_back('l');
    veca.push_back('l');
    veca.push_back('o');
    cout << "Add five elements:Hello" << endl << "result:" << veca << " size:" << veca.getSize() << " capacity:" << veca.getCapacity()<<endl;
    CVector vecb,vecc;
    vecb.push_back('H');
    vecb.push_back('i');
    vecc = vecb;

在这段代码(vecc = vecb)之后,问题发生了。我认为复制构造器出了点问题,但我不知道出了什么问题

push_back 函数

void push_back(char c)
    {
        if (size == capacity-1)
        {
            char* temp = new char[2 * capacity];
            for (size_t i = 0; i < capacity; i++)
            {
                temp[i] = sPtr[i];
            }
            delete[] sPtr;
            capacity *= 2;
            sPtr = temp;
            
        }
        sPtr[size] = c;
        size++;
     
    }

我可以将 *temp 本地指针分配给 *sPtr(指向我的向量的数组的指针)吗

标签: c++visual-studio

解决方案


在您的复制构造函数中,您分配vec.size字节,但设置capacityvec.capacity. 您可能想要分配vec.capacity字节。

接下来是,复制构造和复制分配之间存在差异:

CVector vecb(veca); // this calls the copy constructor
CVector vecc; // this calls the default constructor
vecc = vecb; // this calls the copy assignment operator

由于您没有给出复制赋值运算符的实现,编译器将为您生成一个,看起来像这样:

CVector & operator = (const CVector & other) {
    size = other.size;
    capacity = other.capacity;
    sPtr = other.sPtr;
}

这不适合你,因为

  1. 你失去了sPtr的踪迹,没有人delete知道它。
  2. 现在两个不同CVector的 s 通过 指向同一个内存sPtr。当CVector调用 first 的析构函数时,它将delete sPtr. 然后另一个CVector将指向已经是deleted 的内存。当它的析构函数(或任何其他成员函数)被调用时,它会尝试delete访问或访问该deleted 内存。

这就是规则 3(或规则 5,取决于您是否实现移动语义)的原因。

实现复制(和移动)赋值运算符的一种简单而好的方法是使用复制和交换习语:

void swap(CVector & other) {
    std::swap(size, other.size);
    std::swap(capacity, other.capacity);
    std::swap(sPtr, other.sPtr);
}

CVector & operator = (const CVector& other) {
    CVector tmp(other);       // make a copy of other
    this->swap(other);        // by swapping with other, tmp's destructor, will cleanup your previous sPtr
    return *this;
}

推荐阅读