1

Updated: Thanks for the quick replies. It seems that I have posted an older version of the code. Everything remains the same except for the parameterized constructor. There are a few flaws in the code as you can see, but bare in mind that I am not fully completed with this. Currently I am more worried about the array since this is a new concept introduced yesterday. I have tried several different things and researched this for hours. Most of the responses say to just use the vector class but this is for homework which helps us understand memory allocation and dynamic arrays. Currently this is my .cpp and .h file that is giving me problems. Every time the delete (or the clear function) operation is triggered an error occurs that states blahblah.exe has triggered a break point.

MyVector.h

#pragma once

class MyVector
{
private:
    int arraySize; 
    int arrayCapacity;
    int* theData;
    void grow();

public:
    MyVector();
    MyVector(int n);
    int size() const;
    int capacity() const;
    void clear();
    void push_back(int n);
    int& at(int n);
    ~MyVector();
};

MyVector.cpp

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

    MyVector::MyVector()
    {
    arraySize = 0;
    arrayCapacity = 0; 
    theData = new int[0];
    }
    MyVector::MyVector(int capacityIn)
    {
    theData = new int [capacityIn];
    arraySize = 0;
    arrayCapacity = 0;
    }
    int MyVector::size() const
    {
    return arraySize;
    }
    int MyVector::capacity() const
    {
    return arrayCapacity;
    }
    void MyVector::clear()
    {
        delete [] theData;
        theData = nullptr;
    }
    void MyVector::push_back(int n)
    {
        if (arrayCapacity==0)
        {
        arrayCapacity++;
        MyVector(arrayCapacity);
    }
    if (arraySize == arrayCapacity)
    {
        grow();
        MyVector(arrayCapacity);
    }
    theData[arraySize] = n;
    arraySize++;
}
int& MyVector::at(int index)
{
    if (index >= 0 && index<arraySize)
    {
        return (theData[index]);
    }
    else
    {
        throw index;
    }
}
void MyVector::grow()
{
    arrayCapacity = arrayCapacity + arrayCapacity;
}

MyVector::~MyVector()
{
    if (theData != nullptr)
    {
        clear();
    }
}
greg-mora
  • 29
  • 5
  • 2
    What is the error message? Error messages are pretty important... – tenfour Feb 22 '15 at 22:33
  • 1
    Please produce an [SSCCE](http://www.sscce.org). – Baum mit Augen Feb 22 '15 at 22:35
  • 1
    int* theData = new int [capacityIn]; <-- this is not initializing your data member, this is initializing a local variable with the same name as your data member – Borgleader Feb 22 '15 at 22:35
  • 2
    Your constructor invocations in methods don't make any sense. They won't have any effect on the current object, but create new ones. – lared Feb 22 '15 at 22:35
  • 1
    doctor it hurts when i do this... :p there's a lot of bugs in that code that can cause memory to get trashed. – thang Feb 22 '15 at 22:36
  • 1
    Gee, the compiler gives me *warning: unused variable 'theData'*. How helpful. – chris Feb 22 '15 at 22:39

4 Answers4

5

You have a number of problems I can see already:

  1. You should not be calling the constructor explicitly like this. It doesn't do what you think. Put allocations in a real member function.
  2. Every time you "grow" your array, you just allocate new, causing a leak because the previous pointer wasn't deleted.
  3. The main issue you're asking about: You're not even storing the pointer you allocate in the constructor. Change int* theData = new int [capacityIn]; to theData = new int [capacityIn];. You're doing it correctly in your first constructor for example.
  4. You are not initializing arraySize or arrayCapacity in your second constructor (MyVector(int)).

Nitpicks:

  1. You don't need to check for nullptr before deleting.
  2. There's no need to new int[0]. You should never access the memory, so just initialize it to nullptr.
tenfour
  • 36,141
  • 15
  • 83
  • 142
  • The constructor taking in a capacity also doesn't set `arraySize` or `arrayCapacity`, but should set them both. –  Feb 22 '15 at 22:40
  • Thank you for your help first off. The nullptr check is to verify that I am not deleting anything that I shouldn't be. Which is why if it isn't null then I shouldn't delete (this as introduced by the professor on good coding practice, not sure if it really helps in the real world). I did begin by setting it equal to nullptr but every time I did so, I never was able to point to anything else. Does that make sense? What is the normal syntax for it? – greg-mora Feb 22 '15 at 22:53
  • @ManiacalTeddy `delete[]` itself checks for `nullptr` and won't do anything if it's `nullptr`. – milleniumbug Feb 23 '15 at 01:11
2

Here:

MyVector::MyVector(int capacityIn)
{
  int* theData = new int [capacityIn];
}

You declare a local pointer theData that shadows the theData data member of the current object, leaving it uninitialized. From there, all bets are off on using it, and it is pure happenstance that it is the delete[] where your program finally crashes. Write

MyVector::MyVector(int capacityIn)
{
  theData = new int [capacityIn];
}

instead, and arraySize and arrayCapacity will have to be initialized as well.

Apart from that, you'll run into the problem that

MyVector(arrayCapacity);

in the push_back function allocates a temporary object of type MyVector that is (almost) immediately destroyed again; it does not change the current object.

Wintermute
  • 42,983
  • 5
  • 77
  • 80
  • 1
    *instead, or, better yet, use std::vector instead of naked pointers.* OP specifically mentioned his homework is to make a vector like class... – Borgleader Feb 22 '15 at 22:35
  • 1
    That's not the only problem, though. Even with that fixed, the OP's attempts to grow won't work. –  Feb 22 '15 at 22:36
  • How would i create a permanent object? I believe this is giving me more problems than anything. – greg-mora Feb 22 '15 at 23:21
  • Creating an object, permanent or otherwise, would not help you in this context. You want to change an existing object, not make a new one. This means that constructors do not help you; the object you want to change is already constructed and cannot be constructed a second time. – Wintermute Feb 22 '15 at 23:27
0

This is causing you the problem you cannot solve:

int* theData = new int [capacityIn];

You are saying: "Please define an integer pointer..." and so on. The member variables are different than the variables you are defining inside you methods; it makes no sense to do that. Instead, you should have done that:

theData = new int [capacityIn];

or, just for educational purposes (and in order for you to understand we are assigning to a member variable):

this->theData = new int [capacityIn];

Also (some points may not be that important, but I would like to point them out since you are a new guy):

  1. Please set your other variables in the second constructor, it seems you have forgotten to do so.

    MyVector::MyVector(int capacityIn)
    {
        theData = new int [capacityIn];
        arraySize = capacityIn;
        arrayCapacity = capacityIn;
    }
    
  2. You should have meaningful names, theData is something you should definitely avoid. http://petdance.com/2012/04/the-worlds-two-worst-variable-names/

  3. Your methods should start with a verb, e.g. getDimension() getCapacity() and so on.
  4. Constructors are... constructors, which means they are meant to be called whenever an item is constructed or created. You definitely should not explicitely call a constructor in any way.
  5. This is a basic rule: whenever you access the memory with the new command, you should call delete somewhere after some time. Your code has severe memory leaks.

I might have been able to help you more, but I do not exactly understand what you are trying to accomplish in some methods, namely in grow() and pushBack().

codingEnthusiast
  • 3,800
  • 2
  • 25
  • 37
  • 1
    in fact the ctor-initializer list should be used, then this issue wouldn't even have arisen – M.M Feb 22 '15 at 22:51
0

It's not good style to initialize variables via assignment statements inside the constructor body. Instead, variables should be initialized before the constructor body is entered.

You can either do this by using the member initializer list, or by supplying default values in the class definition. The latter seems easiest here:

class MyVector
{
private:
    int arraySize = 0;
    int arrayCapacity = 0;
    int* theData = nullptr;
    // ....

In the constructor then instead of duplicating code you should leverage existing functions to do the same thing:

MyVector::MyVector(int capacityIn)
{
     // call function which increases capacity to match capacityIn.
}

Currently you don't actually have a function to increase the capacity so you will need to add one. (The grow() function makes the int variable increase but you don't allocate any more memory so this just results in your code writing past the end of the space that is actually allocated).

It might look like:

void grow( int newCapacity )
{
    if ( newCapacity < arrayCapacity )
        return;   // we do not need to shrink

    int *newData = new int [new_capacity];
    if ( arraySize > 0 )
        std::copy(arrayData, arrayData + arraySize, newData);
    delete[] arrayData;
    newData = arrayData;
}

Then you can modify grow() (if you still want to keep that), and push_back() to also call this function.


Note that the clear() function simply needs to do arraySize = 0; . It doesn't need to free any memory; you can leave that capacity available for future use.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • I tried taking some of your advice but again once I hit the delete[] it terminates with a heap error. Here is what I have: void MyVector::grow() { vCapacity = vCapacity + vCapacity; int* tmp = new int[vCapacity]; for (int i = 0; i < vSize; i++) { tmp[i] = vArray[i]; } delete[] vArray; vArray = tmp; } – greg-mora Feb 23 '15 at 00:00
  • @ManiacalTeddy that function looks OK now but perhaps there are still errors elsewhere or in the code that is using this class (since it doesn't follow Rule of Three) – M.M Feb 23 '15 at 00:41