Results 1 to 8 of 8
  1. #1
    Join Date
    Nov 2006
    Location
    Texas
    Posts
    521

    Help with template constructors

    Having a little bit of a problem instanctiating a string template.

    Code:
    1>d:\documents and settings\dod\my documents\visual studio 2008\projects\chap10_excercise_1
    \chap10_excercise_1\array.h(63)
     : error C2082: redefinition of formal parameter 'newSize'
    
    1>d:\documents and settings\dod\my documents\visual studio 2008\projects\chap10_excercise_1
    \chap10_excercise_1\array.h(62)
     : while compiling class template member function 'void Array<T>::resize(int)'
    1>        with
    1>        [
    1>            T=std::string
    1>        ]
    
    1>d:\documents and settings\dod\my documents\visual studio 2008\projects\chap10_excercise_1
    \chap10_excercise_1\array.h(32) 
    : while compiling class template member function 'Array<T>::Array(int)'
    1>        with
    1>        [
    1>            T=std::string
    1>        ]
    
    1>d:\documents and settings\dod\my documents\visual studio 2008\projects\chap10_excercise_1
    \chap10_excercise_1\excercise.cpp(9)
     : see reference to class template instantiation 'Array<T>' being compiled
    1>        with
    1>        [
    1>            T=std::string
    1>        ]
    Class code

    Code:
    //fields
    public:
    		Array();
    		Array(int size);
    		Array(const Array& rhs);
    //methods
    Array<T>::Array()
    {
    	mData = 0;
    	mSize = 0;
    }
    
    template <typename T>
    Array<T>::Array(int size)
    {
    	mData = 0;
    	mSize = 0;
    	resize(size);
    }
    
    template <typename T>
    Array<T>::Array(const Array<T>& rhs)
    {
    	mData = 0;
    	mSize = 0;
    	*this = rhs;
    }
    
    void Array<T>::resize(int newSize)
    {
    	Array(newSize);  // error points here
    }
    main class

    Code:
    	Array<string> stringArray(4);
    	cout << stringArray.size() << endl;

  2. #2
    Join Date
    Jun 2005
    Location
    NY
    Posts
    1,374
    You're creating a new object of Array in resize, which is probably not what you want to do. Plus a template needs to know what type of data it is holding, so your creating a template class with no type info. Its going into the constructor, which is calling resize and creating the new object.

    Why not just put, mSize = newSize; in the resize function?
    CodeGuru: DLL Tutorial For Beginners by me. Rated 4 1/2 out of 5.

  3. #3
    Join Date
    Nov 2006
    Location
    Texas
    Posts
    521
    Having some more problems. What Im trying to do with this template is creat a 1D array of whatever (strings, ints, etc). I need create the array, resize the array, destroy the array, and copy data from an old array to a new array

    Code:
    #ifndef ARRAY_H
    #define ARRAY_H
    using namespace std;
    
    template <typename T>
    class Array
    {
    	public:
    		Array();
    		Array(int size);
    		Array(const Array& rhs);
    		~Array();
    		Array& operator=(const Array& rhs);
    		void resize(int newSize);
    		int size();
    		void destroy();
    		T& operator[](int i);
    	private:
    		T mData; 
    		int mSize; 
    }; //class END braces
    #endif 
    
    template <typename T>
    Array<T>::Array()
    {
    	mData = 0;
    	mSize = 0;
    }
    
    template <typename T>
    Array<T>::Array(int size)
    {
    	mData = size;
    	mSize = size;
    	//resize(size);
    }
    
    template <typename T>
    Array<T>::Array(const Array<T>& rhs)
    {
    	mData = 0;
    	mSize = 0;
    	*this = rhs;
    }
    
    template <typename T>
    Array<T>& Array<T>::operator=(const Array& rhs)
    {
    	if(this == &rhs) 
    		return *this;
    	resize(rhs.mSize);
    
    	for(int i = 0; i < mSize; ++i)
    	{
    		mData[i] = rhs.mData[i];
    	}
    	return *this;
    }
    
    template <typename T>
    void Array<T>::resize(int size)
    {
    	destroy();
    	<T>Array = new <T>Array(size);
    }
    
    template <typename T>
    int Array<T>::size()
    {
    	return mSize;
    }
    
    template <typename T>
    T& Array<T>::operator[](int i)
    {
    	return mData[i];
    }
    
    template <typename T>
    void Array<T>::destroy()
    {
    	if (mData)
    	{
    		delete[] mData;
    	}
    }
    Errors:

    Code:
    1>Excercise.obj : error LNK2019: unresolved external symbol
     "public: __thiscall Array<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::
    ~Array<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(void)"
     (??1?$Array@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QAE@XZ) referenced in function _main
    1>d:\Documents and Settings\dod\My Documents\Visual Studio 2008\Projects\Chap10_Excercise_1\Debug\Chap10_Excercise_1.exe : 
    fatal error LNK1120: 1 unresolved externals

  4. #4
    Join Date
    Nov 2006
    Location
    Texas
    Posts
    521
    Mmk. Forget all code I posted previously. I copied that code out of the book and I dont understand why its written the way it is. So here is the new template I wrote that makes more sense. But it has some problems.

    Code:
    #ifndef ARRAY_H
    #define ARRAY_H
    using namespace std;
    
    template <typename T>
    class Array
    {
    	public:
    		Array();
    		Array(int size);
    		void resize(int newSize);
    		int size();
    		void destroy(Array<T>* rhs);
    		T& operator[](int i);
    	private:
    		int Size; 
    }; //class END braces
    #endif 
    
    template <typename T>
    Array<T>::Array()
    {
    	Size = 0;
    }
    
    template <typename T>
    Array<T>::Array(int size)
    {
    	Array<T> ray = new Array[size];
    	Size = size;
    }
    
    template <typename T>
    void Array<T>::resize(int size)
    {
    	destroy();
    	<T>Array <T>array = new <T>Array(size);
    }
    
    template <typename T>
    int Array<T>::size()
    {
    	return Size;
    }
    
    template <typename T>
    void Array<T>::destroy(Array<T>* rhs)
    {
    	if (Size)
    	{
    		delete[] rhs;
    	}
    }
    For now there is one error Im sure theres more.

    Code:
    array.h(29) : error C2440: 'initializing' : cannot convert from 'Array<T> *' to 'Array<T>'
    1>        with
    1>        [
    1>            T=std::string
    1>        ]
    1>        No constructor could take the source type, or constructor overload resolution was ambiguous
    while compiling class template member function 'Array<T>::Array(int)'
    1>        with
    1>        [
    1>            T=std::string
    1>        ]
    excercise.cpp(9) : see reference to class template instantiation 'Array<T>' being compiled
    1>        with
    1>        [
    1>            T=std::string
    1>        ]
    The code I posted in the main.cpp file is still the scroll up to see it.

  5. #5
    Join Date
    Oct 2005
    Location
    Seattle, WA
    Posts
    501
    The implementation in post #3 is correct. The compiler is just geeking out because you never defined the destructor.

  6. #6
    Join Date
    Nov 2006
    Location
    Texas
    Posts
    521
    I put in a destructor and the error still persists.

  7. #7
    Join Date
    Oct 2005
    Location
    Seattle, WA
    Posts
    501
    My bad, I didn't thoroughl look through the code or try it with a string. It compiled with no errors using an int, so I figured problem solve. Examining the code it looks like there is another error, actually several.

    You have declared:
    Code:
    T mData;
    This is the same as declaring "int mData" or "string mData" in that you only get one of the item, yet you are trying to construct an array of the items. This would make more sense if you changed mData to a pointer of type T.
    Code:
    T* mData;
    Of course now all member functions need to be changed to deal with a pointer. Consequently, you will have to allocate and deallocate memory as needed.
    Code:
    template <typename T>
    Array<T>::Array(int size)
    {
       mData = new T[size];
       mSize = size;
    }
    


  8. #8
    Join Date
    Oct 2005
    Location
    Seattle, WA
    Posts
    501
    I decided to put my money where my mouth is and actually make this work rather than just give you pointers on what needs to be done. There are a couple of caveats though. I made the assumption you were trying to create a dynamic array, and I tried to keep as much of your code intact as possible. Also, not knowing the exact requirements I did make a few design decisions of my own.

    I added a counter (mCurrentElem) to track the end of the data. Its value should equal number of elements in the array, as well as be an index to the next open position. By this I mean, if there are 5 elements in a 0 based array, the 5th element is at mData[4]. Hence, mCurrentElem = 5, and the next open data position is mData[5]. So adding a new element can be accomplished be assigning the data to mData[mCurrentElem++].

    I added functions to add and remove data from the end of the list. These make the most sense for a dynamic array.

    There is a destinction being made internally, between the actual size of the array and the total number of elements. The user only has access to the total number of elements. This is the size that gets reported. The real size of the array will aways be bigger than the total elements, and it will grow automaticly as needed. For simplicity I picked a grow size of 5. Each time mData needs to expand it gets larger by this amount. This reduces the number of times new memory needs to be allocated and the number of times the data needs to be copied from old memory to new memory. Following along the same lines I decided not to shrink the actually size of the array. If you resize the array smaller mCurrentElem gets moved, but the actual size of the array does not change. I did this in part to reduce memory allocations and copying, but also because it was easy.

    Array.h
    Code:
    #ifndef ARRAY_H
    #define ARRAY_H
    using namespace std;
    template <typename T>
    class Array
    {
        public:
            Array();
            Array(int size);
            Array(const Array& rhs);
            ~Array();
            Array<T>& operator=(const Array<T>& rhs);
            void resize(int newSize);
            int size() const;
            void destroy();
            T& operator[](int i) const;
            void push_back(T elem);
            T& pop_back();
     
        private:
            void copyData(T* src, T* dst);
            void growData();
            T* mData; 
            int mSize; 
            int mCurrentElem;
            int mGrowSize;
    }; //class END braces
    #endif 
     
    template <typename T>
    Array<T>::Array()
    {
        mData = 0;
        mSize = 0;
        mCurrentElem = 0;
        mGrowSize =5;
    }
     
    template <typename T>
    Array<T>::Array(int size)
    {
        mData = new T[size];
        mSize = size;
        mCurrentElem = 0;
        mGrowSize = 5;
    }
     
    template <typename T>
    Array<T>::Array(const Array<T>& rhs)
    {
        destroy();
        mSize = rhs.mSize;
        mData = new T[mSize];
        mCurrentElem = rhs.mCurrentElem;
        mGrowSize = rhs.mGrowSize;
        copyData(rhs.mData, mData);
    }
     
    template <typename T>
    Array<T>::~Array()
    {
        destroy();
    }
     
    template <typename T>
    Array<T>& Array<T>::operator=(const Array<T>& rhs)
    {
        if(this == &rhs) 
            return *this;
        resize(rhs.mSize);
        mCurrentElem = rhs.mCurrentElem;
        for(int i = 0; i < mCurrentElem; ++i)
        {
            mData[i] = rhs.mData[i];
        }
        return *this;
    }
     
    template <typename T>
    void Array<T>::resize(int size)
    {
        if (size < mCurrentElem)
            mCurrentElem = size;
        else if (size > mSize)
        {
            T* newData = new T[size];
            copyData(mData, newData);
            delete [] mData;
            mData = newData;
        }
    }
     
    template <typename T>
    int Array<T>::size() const
    {
        return mCurrentElem;
    }
     
    template <typename T>
    T& Array<T>::operator[](int i) const
    {
        return mData[i];
    }
     
    template <typename T>
    void Array<T>::destroy()
    {
        delete [] mData;
    }
     
    template <typename T>
    void Array<T>::push_back(T elem)
    {
        if (mCurrentElem == mSize)
            growData();
        mData[mCurrentElem++] = elem;
    }
     
    template <typename T>
    void Array<T>::copyData(T *src, T* dst)
    {
        for(int inx = 0; inx < mCurrentElem; ++inx)
            dst[inx] = src[inx];
    }
     
    template <typename T>
    void Array<T>::growData()
    {
        mSize += mGrowSize;
        T* newData = new T[mSize];
        copyData(mData, newData);
        delete [] mData;
        mData = newData;
    }
     
    template <typename T>
    T& Array<T>::pop_back()
    {
        return mData[--mCurrentElem];
    }
    Simple test app:
    Code:
    #include <iostream>
    #include "Array.h"
    #include <string>
     
    void printArray(const Array<std::string>& arr);
     
    int main(void)
    {
        Array<std::string> strArray;
        strArray.push_back(std::string("elem1"));
        strArray.push_back("elem2");
        printArray(strArray);
     
        Array<std::string> copyArray;
        copyArray.push_back("copyArray before copy");
        printArray(copyArray);
     
        copyArray = strArray;
        std::cout << "copyArray:" << std::endl;
        printArray(copyArray);
     
        std::cout << std::endl << "strArray:" << std::endl;
        printArray(strArray);
     
        std::cout << "Remove item: " << strArray.pop_back() << std::endl;
        printArray(strArray);
     
        return 0;
    }
     
    void printArray(const Array<std::string>& arr)
    {
        for(int inx = 0; inx < arr.size(); ++inx)
            std::cout << arr[inx] << std::endl;
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •