1
votes

I need a template Function to resize an Array of any type.

Here is my try:

   class CCommon
    {
    template < typename T >
    static void ResizeArray(T* paArray, int iOldSize, int iNewSize, T tInitValue);
    }
    
    ..
    
   template < typename T >
   void CCommon::ResizeArray(T* paArray, int iOldSize, int iNewSize, T tInitValue)
    {
       T* paTmpArray = new T[iOldSize];
       for(int i = 0; i < iOldSize; i++)
       {
          paTmpArray[i] = paArray[i];
       }
       delete [] paArray;
       paArray=new T[iNewSize];
       for(int i=0; i < iNewSize; i++)
       {
          paArray[i] = tInitValue;
       }
       for(int i = 0; i < iOldSize; i++)
       {
          paArray[i] = paTmpArray[i];
       }
       delete [] paTmpArray;
    }

The CCommon File is even compilable, but if i want to use it i get the Error:

Fehler 2 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ("unresolved external references".)

""public: static void __cdecl CCommon::ResizeArray(int *,int,int,int)" (??$ResizeArray@H@CCommon@@SAXPAHHHH@Z)" in Funktion ""public: void __thiscall CWaebi_OBJ::ReInit(void)" (?ReInit@CWaebi_OBJ@@QAEXXZ)". CWaebi_OBJ.obj

Fehler 3 fatal error LNK1120: 1 nicht aufgelöste externe

This is how i want to call it:

#include CCommon

SomeFunction
{
..
CCommon::ResizeArray<BOOL>( mTextIndexMask, m_iNumberOfLastTextMaskArray, mTextCount, FALSE );
..
}

What is wrong?

regards camelord

5
Most SO users won't be able to read the error messages.Marcelo Cantos
“unresolved external references”.kennytm
And yet another template definition in a .cpp file.Scharron
You probably want to pass the pointer by reference --not related to the question, but a bug none-the-less--. Also your function is costly (you are copying more than you need) and not exception-safe in any way.David Rodríguez - dribeas
@Donotalo: "Verweis auf nicht..." is German; "??$ResizeArray@H@CCommon@@SAXPAHHHH@Z" is the binary language of moisture vaporators.Mike Seymour

5 Answers

3
votes

First of all, why on Earth are you using some custom BOOL type instead of C++'s built-in bool?

Secondly, it sounds like you have placed the template implementation in a source file. Is the implementation of CCommon::ResizeArray in the ccommon.h file that you are including in the where you call it? If not, put it there (or in a file included by it). Templates need to have their entire implementation in header files to work. You can't have the declaration in the header and the definition in a source file like with normal functions and methods.

1
votes
template < typename T >
void CCommon::ResizeArray(T* paArray, int iOldSize, int iNewSize, T tInitValue)
{
 T* paTmpArray = new T[iOldSize];
 for(int i = 0; i < iOldSize; i++)
 {
  paTmpArray[i] = paArray[i];
 }
 delete [] paArray;
 paArray=new T[iNewSize];
 for(int i=0; i < iNewSize; i++)
 {
  paArray[i] = tInitValue;
 }
 for(int i = 0; i < iOldSize; i++)
 {
  paArray[i] = paTmpArray[i];
 }
 delete [] paTmpArray;
}

That's not going to work. After call to that function value of paArray will not be changed. You'll get a memory leak, plus paArray will be pointing to garbage after that call. Also, you don't need to make it a static class function. Using template function is enough. And you don't need temporary array.

Use something like this:

#include <stdio.h>

template <typename T> void resizeArray(T*& arr, int oldSize, int newSize, const T initVal){
    T* newArray = new T[newSize];

    for (int i = 0; (i < oldSize)&&(i<newSize); i++)
        newArray[i] = arr[i];

    for (int i = oldSize; i < newSize; i++)
        newArray[i] = initVal;

    delete[] arr;
    arr = newArray;
}

int main(int argc, char** argv){
    const int startSize = 26, newSize = 42;
    int* p = new int[startSize];
    for (int i = 0; i < startSize; i++)
        p[i] = i;

    resizeArray(p, startSize, newSize, 87);

    for (int i = 0; i < newSize; i++)
        printf("%d\n", p[i]);
    delete[] p;
    return 0;
}

or this:

#include <stdio.h>
#include <algorithm>

template <typename T> void resizeArray(T*& arr, int oldSize, int newSize, const T initVal){
    T* newArray = new T[newSize];

    std::copy(arr, arr+std::min(oldSize, newSize), newArray);

    if (oldSize < newSize)
        std::fill(newArray+oldSize, newArray+newSize, initVal);

    delete[] arr;
    arr = newArray;
}

int main(int argc, char** argv){
    const int startSize = 26, newSize = 42;
    int* p = new int[startSize];
    for (int i = 0; i < startSize; i++)
        p[i] = i;

    resizeArray(p, startSize, newSize, 87);

    for (int i = 0; i < newSize; i++)
        printf("%d\n", p[i]);
    delete[] p;
    return 0;
}

instead.

1
votes

I guess you are trying to define your template member function in a .cpp file. This is bad. Templates depends on types resolved at instantiation time, having the full definition to produce correct code. Solution: put your definition in a .hxx file, included by your .h .

1
votes

Once you've fixed the template in cpp problem (@Tyler McHenry), your ResizeArray still won't work, because you're never returning your newly allocated array to the caller. Either you have to return it, or take in a T** as the argument.

1
votes

It seems like you try to put the implementation in the *.cpp file. Templates have to be implemented in the header.

Another point is the fact that your code has a major bug in it: You don't return the new pointer at all, you only overwrite the local copy of your parameter. This means that the newly allocated memory is leaked and any code trying to access the array afterwards will probably crash.

Oh and another tip: why exactly are you copying your array contents into a temporary variable? you could just allocate an array of the new size, copy the contents into that one, delete the old array and either return the new pointer or make pArray a T** and assign the new arraypointer to that one.

As a last point I would suggest using the std::copy and std::fill operations for copying /filling the array contents, e.g.: instead of

for(int i = 0; i < iOldSize; i++)
{
    paTmpArray[i] = paArray[i];
}

use

std::copy(paArray, paArray+iOldSize, paTmpArray);

It leads to less and more consise code and is probably more optimized then doing it in a loop.

So here is how i would suggest to do this:

#include <algorithm>
template < typename T >
void CCommon::ResizeArray(T*& paArray, int iOldSize, int iNewSize, T tInitValue)
{
 T* paTmpArray = new T[iNewSize];
 std::copy(paArray, paArray + std::min(iNewSize, iOldSize), paTmpArray);
 delete[] paArray;
 if(iNewSize > iOldSize)
     std::fill(paTmpArray + iOldSize, paTmpArray + iNewSize, tInitValue);
 paArray = paTmpArray;
}