自定义向量类中的堆损坏错误

时间:2016-08-06 02:43:35

标签: c++ heap heap-corruption

我从我编写的代码中收到运行时错误。当我调用grow()函数时,它会完美地运行,直到它到达delete,然后崩溃并说:

Error I am getting

这让我很困惑,我不明白这是怎么回事。

以下是我的代码:

.cpp文件

#include "MyVector.h"
#include <cstdlib>;
void MyVector::grow()
{

    if (cap == 0)
        cap = MINCAP;
    else
        cap = cap*MINCAP;
    int* temp = new int[cap];

    for (int i = 0; i < vectorSize; i++)
    {
        temp [i] = theVector[i];
    }
    for (int i = vectorSize; i < cap; i++)
    {
        temp[i] = 0;
    }
    delete[] theVector;
    theVector = temp;

}

MyVector::MyVector()
{
    clear();
}

MyVector::~MyVector()
{
    delete[] this->theVector;

}

MyVector::MyVector(int _cap)
{
    cap = _cap;
    for (int i = 0; i < cap; i++)
    {
        this->theVector[i] = 0;
    }
}

MyVector::MyVector(const MyVector & vect)
{
    this->vectorSize = vect.vectorSize;
    this->cap = vect.cap;
    delete[] theVector;
    theVector = new int[cap];
    for (int i = 0; i < vectorSize; i++)
    {
        this->theVector[i] = vect.theVector[i];
    }
    for (int i = vectorSize; i < cap; i++)
    {
        this->theVector[i] = 0;
    }
}

int MyVector::size() const
{
    return vectorSize;
}

int MyVector::capacity() const
{
    return cap;
}

void MyVector::clear()
{
    vectorSize = 0;
    cap = MINCAP;
    delete[] theVector;
    theVector = new int[MINCAP];
    for (int i = 0; i <MINCAP; i++)
    {
        *(theVector + i) = 0;
    }
}
//Put an int into the vector
void MyVector::push_back(int n)
{
    if (theVector == nullptr)
        clear();
    if (vectorSize+1 >= cap) 
    {
        grow();
        theVector[vectorSize] = n;
        vectorSize++;
    }
    else 
    {
        theVector[vectorSize] = n;
        vectorSize++;
    }

}

int MyVector::at(int _location)
{
    if (_location < 0 || _location >= vectorSize)
        throw _location;

    return theVector[_location];
}

MyVector & MyVector::operator=(const MyVector & rho)
{
    // test for self assignment
    if (this == &rho)
        return *this;

    // clean up array in left hand object (this)
    delete[] this->theVector;

    // create a new array big enough to hold right hand object's data
    this->vectorSize = rho.size();
    this->cap = rho.cap;
    this->theVector = new int[cap];
    // copy the data
    for (int i = 0; i < vectorSize; i++)
    {
        this->theVector[i] = rho.theVector[i];
    }
    for (int i = vectorSize; i < cap; i++)
    {
        this->theVector[i] = 0;
    }
    // return this object
    return *this;
}

The.h文件

#pragma once
#include <array>
#include <fstream>
using namespace std;
class MyVector
{
private:
    //the minimum capacity of the vector
    const int MINCAP = 2;
    //the amount of items in the vector
    int vectorSize = 0;
    //the maximum ammount of items in the vector
    int cap = MINCAP;
    //The pointer to the first integer in the vector
    int* theVector = new int[MINCAP];
    //The grow function
    //Parameters : none
    //returns : none
    void grow();
public:
    //The nonparmeterized constructor
    //Parameters : none
    //returns :none
    MyVector();
    //The deconstructor
    //Parameters : none
    //returns : none
    ~MyVector();
    // The parameterized constructor
    //Parameters : the capacity to set it to
    //returns : none
    MyVector(int _cap);
    //Get the size
    //Parameters : none
    //returns : the size
    MyVector(const MyVector& vect);
    //Get the size
    //Parameters : none
    //returns : the size
    int size() const;
    //get the capacity 
    //Parameters : none
    //returns : cap
    int capacity() const;
    //clear the data
    //Parameters : none
    //returns :none
    void clear();
    //insert an int into the vector
    //Parameters : the int
    //returns : none
    void push_back(int n);
    //gets the int at a location
    //Parameters : the location
    //returns : the integer
    int at(int _location);
    //Overload the = operator
    //Parameters : the one to copy
    //returns : the vector
    MyVector& operator=(const MyVector& rho);
    //Overload the << operator
    //Parameters : the one to copy
    //returns : the vector
    friend ostream& operator<<(ostream& os, MyVector& TheVector)
    {
        for (int i = 0; i < TheVector.size(); i++)
        {
            os << TheVector.at(i) << ", ";
        }

        return os;
    }



};

测试它的驱动程序。

#include <iostream>
#include "MyVector.h"     
using namespace std;

// the printV function
// used to test the copy constructor
// parameter: a MyVector object
void printV(MyVector);

int main()
{
    cout << "\nCreating a vector Sam of size 4.";
    MyVector sam(4);

    cout << "\nPush 12 values into the vector.";
    for (int i = 0; i < 12; i++)
        sam.push_back(i);

    cout << "\nHere is sam: ";
    cout << sam;
    cout << "\n---------------\n";

    cout << "\nCreating a vector Joe of size 4.";
    MyVector joe(4);
    cout << "\nPush 6 values into the vector.";
    for (int i = 0; i < 6; i++)
        joe.push_back(i * 3);

    cout << "\nHere is joe: ";
    cout << joe;
    cout << "\n---------------\n";

    cout << "\nTest the overloaded assignment operator \"joe = sam\": ";
    joe = sam;

    cout << "\nHere is sam: ";
    cout << sam;
    cout << "\n---------------\n";

    cout << "\nHere is joe: ";
    cout << joe;
    cout << "\n---------------\n";

    // pass a copy of sam by value
    printV(sam);


    cout << endl;
    system("PAUSE");
    return 0;
}

void printV(MyVector v)
{
    cout << "\n--------------------\n";
    cout << "Printing a copy of a vector\n";
    cout << v;
}

编辑:我用建议更新了代码。

1 个答案:

答案 0 :(得分:4)

您的代码存在一些问题:

  1. 您的MyVector(int)构造函数未分配所请求的数组元素数。它甚至根本没有触及theVector,因此theVector被成员初始化为默认的MINCAP元素,即使请求的cap实际上更高。

  2. 您的MyVector(MyVector&)复制构造函数声明错误。要成为一个合适的拷贝构造函数,它需要通过 const 引用来获取输入对象。没有它,你没有适当的拷贝构造函数。如果编译器生成自己的默认复制构造函数,它只会将theVector指针从一个对象复制到另一个对象,而不是实际创建数组数据的新副本,从而导致所有权问题。

  3. 例如,您的printV()函数按值输入MyVector ,它复制构造一个临时对象。当临时超出范围并在其delete[]指针上调用theVector时,如果使用编译器的默认复制构造函数,它实际上将销毁原始MyVector对象中的数组。你需要一个合适的拷贝构造函数。

  4. clear()正在使用delete而不是delete[]。分配有new 的内存必须delete释放。分配有new[] 的内存必须delete[]释放。它们不匹配会导致内存问题。

  5. 话虽如此,我建议以下实施:

    #pragma once
    #include <iostream>
    
    class MyVector
    {
    private:
        //the minimum capacity of the vector
        const int MINCAP = 2;
    
        //the number of items in the vector
        int vectorSize = 0;
    
        //the maximum number of items in the vector
        int cap = 0;
    
        //The pointer to the first integer in the vector
        int* theVector = nullptr;
    
        //The grow function
        //Parameters : none
        //returns : none
        void grow();
    
    public:
        //The nonparmeterized constructor
        //Parameters : none
        //returns :none
        MyVector();
    
        // The parameterized constructor
        //Parameters : the capacity to set it to
        //returns : none
        MyVector(int _cap);
    
        // The copy constructor
        //Parameters : the vector to copy from
        //returns : none
        MyVector(const MyVector& src);
    
        // The move constructor
        //Parameters : the vector to move from
        //returns : none
        MyVector(MyVector&& src);
    
        //The destructor
        //Parameters : none
        //returns : none
        ~MyVector();
    
        //Get the size
        //Parameters : none
        //returns : the size
        int size() const;
    
        //get the capacity 
        //Parameters : none
        //returns : cap
        int capacity() const;
    
        //clear the data
        //Parameters : none
        //returns :none
        void clear();
    
        //insert an int into the vector
        //Parameters : the int
        //returns : none
        void push_back(int n);
    
        //gets the int at a location
        //Parameters : the location
        //returns : the integer
        int at(int _location);
    
        //swap the content of a vector with another
        //Parameters : the vector to swap with
        //returns : none
        void swap(MyVector& other);
    
        //Overload the copy = operator
        //Parameters : the one to copy from
        //returns : the vector
        MyVector& operator=(const MyVector &rho);
    
        //Overload the move = operator
        //Parameters : the one to move from
        //returns : the vector
        MyVector& operator=(MyVector && rho);
    
        //Overload the << operator
        //Parameters : the one to print
        //returns : the stream
        friend std::ostream& operator<<(std::ostream& os, const MyVector& rho);
    };
    
    std::ostream& operator<<(std::ostream& os, const MyVector& rho);
    
    void swap(MyVector &v1, MyVector &v2) { v1.swap(v2); }
    
    namespace std {
        template <>
        void swap(MyVector &v1, MyVector &v2)
        {
                v1.swap(v2);
        }
    }
    

    #include "MyVector.h"
    #include <algorithm>
    #include <utility>
    
    MyVector::MyVector()
        : MyVector(MINCAP)
    {
    }
    
    MyVector::MyVector(int _cap)
        : theVector(new int[_cap]), cap(_cap)
    {
        std::fill_n(theVector, cap, 0);
    }
    
    MyVector::MyVector(const MyVector & src)
        : theVector(new int[src.cap]), cap(src.cap), vectorSize(src.vectorSize)
    {
        std::copy_n(src.theVector, vectorSize, theVector);
        std::fill_n(theVector+vectorSize, cap-vectorSize, 0);
    }
    
    MyVector::MyVector(MyVector && src)
    {
        src.swap(*this);
    }
    
    MyVector::~MyVector()
    {
        delete[] theVector;
    }
    
    void MyVector::grow()
    {
        int newcap = cap;
        if (newcap == 0)
            newcap = MINCAP;
        else
            newcap = newcap * MINCAP;
    
        int* newVector = new int[newcap];
    
        std::copy_n(theVector, vectorSize, newVector);
        std::fill_n(newVector+vectorSize, newcap-vectorSize, 0);
    
        delete[] theVector;
        theVector = newVector;
        cap = newcap;
    }
    
    int MyVector::size() const
    {
        return vectorSize;
    }
    
    int MyVector::capacity() const
    {
        return cap;
    }
    
    void MyVector::clear()
    {
        *this = MyVector();
    }
    
    void MyVector::push_back(int n)
    {
        if (vectorSize >= cap) 
            grow();
    
        theVector[vectorSize] = n;
        ++vectorSize;
    }
    
    int MyVector::at(int _location)
    {
        if ((_location < 0) || (_location >= vectorSize))
            throw _location;
    
        return theVector[_location];
    }
    
    void MyVector::swap(MyVector& other)
    {
        std::swap(theVector, other.theVector);
        std::swap(cap, other.cap);
        std::swap(vectorSize, other.vectorSize);
    }
    
    MyVector& MyVector::operator=(const MyVector &rho)
    {
        if (this != &rho)
        {
            int newcap = rho.cap;
            if (cap != newcap)
            { 
                delete[] theVector;
                theVector = nullptr;
                cap = 0;
                vectorSize = 0;
    
                theVector = new int[newcap];
                cap = newcap;
            }
    
            int newsize = rho.vectorSize;
            std::copy_n(rho.theVector, newsize, theVector);
            std::fill_n(theVector+newsize, cap-newsize, 0);
            vectorSize = newsize;
        }
    
        return *this;
    }
    
    MyVector& MyVector::operator=(MyVector && rho)
    {
        rho.swap(*this);
    
        return *this;
    }
    
    std::ostream& operator<<(std::ostream& os, const MyVector& rho)
    {
        os << "size " << rho.vectorSize << ", capacity " << rho.cap;
        if (rho.vectorSize > 0)
        {
            os << "\n" << rho.theVector[0];
            for (int i = 1; i < rho.vectorSize; ++i)
            {
                os << ", " << rho.theVector[i];
            }
        }
    
        return os;
    }
    

    #include <iostream>
    #include "MyVector.h"     
    
    // the printV function
    // used to test the copy constructor
    // parameter: a MyVector object
    void printV(MyVector);
    
    int main()
    {
        std::cout << "\nCreating a vector Sam of capacity 4.";
        MyVector sam(4);
    
        std::cout << "\nPush 12 values into the vector.";
        for (int i = 0; i < 12; ++i)
            sam.push_back(i);
    
        std::cout << "\nHere is sam: ";
        std::cout << sam;
        std::cout << "\n---------------\n";
    
        std::cout << "\nCreating a vector Joe of capacity 4.";
        MyVector joe(4);
    
        std::cout << "\nPush 6 values into the vector.";
        for (int i = 0; i < 6; ++i)
            joe.push_back(i * 3);
    
        std::cout << "\nHere is joe: ";
        std::cout << joe;
        std::cout << "\n---------------\n";
    
        std::cout << "\nTest the overloaded copy assignment operator \"joe = sam\": ";
        joe = sam;
    
        std::cout << "\nHere is sam: ";
        std::cout << sam;
        std::cout << "\n---------------\n";
    
        std::cout << "\nHere is joe: ";
        std::cout << joe;
        std::cout << "\n---------------\n";
    
        std::cout << "\nTest the overloaded move assignment operator \"joe = MyVector(5)\": ";
        joe = MyVector(5);
    
        std::cout << "\nHere is joe: ";
        std::cout << joe;
        std::cout << "\n---------------\n";
    
        // pass a copy of sam by value
        printV(sam);
    
        std::cout << std::endl;
    
        system("PAUSE");
        return 0;
    }
    
    void printV(MyVector v)
    {
        cout << "\n--------------------\n";
        cout << "Printing a copy of a vector\n";
        cout << v;
    }