hi guys,
i want to do this task given by ebook :

Modify the SimpleVector class template presented in this chapter to include the
member functions push_back and pop_back. These functions should emulate the
STL vector class member functions of the same name. (See Table 16-5.) The
push_back function should accept an argument and insert its value at the end of the
array. The pop_back function should accept no argument and remove the last element
from the array. Test the class with a driver program.

then i design push_back and pop_back function for the SimpleVector class :

this is the push_back function =

//aptr is the private member variables, and so does arraySize.
template <class Type>
void SimpleVector<Type>::push_back(int x)
{
    if(arraySize > 0)
    {
        Type* temp = new Type[arraySize];
        for(int index = 0; index < arraySize; index++)
        {
            temp[index] = aptr[index];
        }
        delete [] aptr;
        arraySize += 1;

        aptr = new Type[arraySize];
        for(int index = 0; index < arraySize - 1; index++)
        {
            aptr[index] = temp[index];
        }
        delete [] temp;
        aptr[arraySize - 1] = x;
    }

    else
    {
        arraySize = 1;
        aptr = new Type[arraySize];
        aptr[0] = x;
    }
 }

and this is the pop_back function:

//aptr is the private member variables, and so does arraySize.
template <class Type>
void SimpleVector<Type>::pop_back()
{
    arraySize -= 1;
    Type* temp = new Type[arraySize];

    for(int index = 0; index < arraySize; index++)
    {
        temp[index] = aptr[index];
    }

    delete [] aptr;

    aptr = new Type[arraySize];

    for(int index = 0; index < arraySize; index++)
    {
        aptr[index] = temp[index];
    }
}

my questions are:
- is it correct way to perform push_back and pop_back just like in the STL vector(i tried it and it works, but i dont know if the functions will/wont produce errors)? because i think my push_back and pop_back functions looked awkward :S
- why does my main function need to includes "SimpleVector.h" and "SimpleVector.cpp" ? if it only includes "SimpleVector.h", my main function wont recognize the SimpleVector class template, why does it happen?

note : sorry for the bad english

Recommended Answers

All 10 Replies

I will help you out with what I can see from a quick glance. #1: Your vector stores generic 'Type' variables, so unless all of your vectors are vector<int> then you need your push_back function to take a Type value. Also you make a critical error that I used to make all the time with dynamic memory allocation. Here is how to do it properly:

Type *tempArray=new Type[arraySize];
for (size_t i=0; i<arraySize; ++i)
    tempArray[i]=sourceArray[i];//up until here we did the same thing
tempArray[arraySize++]=newValue;//this is pretty simple, you increase the array size, but return the old size to the [] operator, basically appending the value AND updating the size variable.
delete[]sourceArray;//we don't need it anymore
//here you re-allocated sourceArray and copied tempArray to it. You do not have to do it
sourceArray=tempArray;//now since the pointers are equal sourceArray will contain the contents tempArray.

You would think that since tempArray is about to go out of scope sourceArray will be invalid... you would be right if it was sourceArray=&tempArray because it is true tempArray will be deleted. The thing is that tempArray stores 1 int, corresponding to the location in memory of the array. That int is also in sourceArray. As such it still holds the same data as before!

erm btw, i got runtime errors when using this code:

Type *tempArray=new Type[arraySize];

for (size_t i=0; i<arraySize; ++i)

tempArray[i]=sourceArray[i];//up until here we did the same thing

tempArray[arraySize++]=newValue;//this is pretty simple, you increase the array size, but return the old size to the [] operator, basically appending the value AND updating the size variable.

delete[]sourceArray;//we don't need it anymore

//here you re-allocated sourceArray and copied tempArray to it. You do not have to do it
sourceArray=tempArray;//now since the pointers are equal sourceArray will contain the contents tempArray.

and :

    size_t //Eerm, what is size_t?

size_t //Eerm, what is size_t?

It's a typedef for an undisclosed unsigned integer type (usually int or long). It's defined in <cstddef> along with a number of other C-inherited headers, and the intended usage is as the result type of the sizeof operator.

Since sizeof is often used to calculate the number of elements in an array, it also makes sense to use size_t as the index variable type.

Also it didn't work because it was an example, it just so happens that you type is called Type, but you should have noticed that I was making an example by the variable names. You need to think to program. It is always tempting to copy and paste, but don't do it. Learn the concept, understand it, then apply it. Even if you find a section of useful code that you can copy and paste and it works, you will find yourself constantly searching for the example every time you need it. If you learnt what the example was trying to say then you could recreate it in seconds flat.

edit see below

At line 106 of your last post, you need to allocate size for 1 more element than the current array-size. As so:

Type* temp = new Type[arraySize + 1];

That's what caused the run-time error.

Also, you should note that in your push-back function, you don't actually need to check for arraySize to be 0 because if it is, the for-loop at line 107 will not execute and the deletion of the aptr will not do anything because deleting a NULL pointer has no effect. For this to work, you have to make sure that whenever arraySize is 0 that the aptr pointer is also NULL. For example, your constructor should do this:

template <class Type>
SimpleVector<Type>::SimpleVector(int s)
{
    arraySize = s;
    // Check if arraySize is 0, if it is, then you set aptr to NULL and return:
    if(arraySize == 0)
    {
      aptr = NULL;
      return;
    };
    try
    {
        aptr = new Type[arraySize];
    }
    catch(std::bad_alloc)
    {
        memError();
    }
    for(int count = 0; count < arraySize; count++)
    {
        *(aptr + count) = 0;
    }
}

You should do something similar in the other constructor, as well as your resize and pop-back function should check if the new size is 0 and if it is, set the aptr pointer to NULL.

Once you can guarantee that whenever arraySize == 0 then aptr == NULL, then you can use the fact that deleting a null-pointer is OK (won't actually do anything), and simplify your destructor to this:

template <class Type>
SimpleVector<Type>::~SimpleVector()
{
    delete [] aptr;  // if aptr is NULL, this will have no effect.
}

And, then, your push-back function can be simplified to this:

template <class Type>
void SimpleVector<Type>::push_back(const Type& x)  // notice you should take a Type value.
{
    Type* temp = new Type[arraySize + 1];
    for(int index = 0; index < arraySize; index++) // if arraySize == 0, this will not execute.
        temp[index] = aptr[index];
    temp[arraySize++] = x;
    delete [] aptr;          // if aptr is NULL this will have no effect.
    aptr = temp;
}

As for your pop-back function, you should notice that the improvement that was done to the push-back function (avoiding a double allocation and copying of memory) can also be done in the pop-back function in a similar way. But, remember, you have to check if the new size is 0 and set aptr to NULL if that is the case (after deleting what it originally pointed to).

EDIT: As for the reason why you can't separate the class template definitions (cpp file) from the class declaration (header), please read this explanation.

ok i change the functions to this :

template <class Type>
void SimpleVector<Type>::push_back(const Type& x)
{

        Type* temp = new Type[arraySize + 1];
        for(int index = 0; index < arraySize; index++)
        {
            temp[index] = aptr[index];
        }
        temp[arraySize++] = x;

        delete [] aptr;

        aptr = temp;

}

template <class Type>
void SimpleVector<Type>::pop_back()
{
    if(arraySize == 0 || aptr == NULL)
    {
        std::cout<<"cannot pop back! \n";
        return;
    }
    Type* temp = new Type[arraySize];

    for(int index = 0; index < arraySize; index++)
    {
        temp[index] = aptr[index];
    }
    temp[arraySize--];

    delete [] aptr;

    aptr = temp;
}

thx guys! :D

EDIT:

Is it okay if i change my push_back function to this :

template <class Type>
void SimpleVector<Type>::push_back(const Type& x)
{
        if(arraySize > 0 || aptr != NULL)
        {
            aptr[arraySize++] = x;
        }
        else
        {
            arraySize = 1;
            aptr = new Type[arraySize];
            aptr[0] = x;
        }

}

Is it okay if i change my push_back function to this :

No it is not! The pointer aptr does not point to enough memory to store the added value. Stick to the previous version.

okay done! really great thx to u all guys :D

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.