0

I'm trying to implement my own vector class as an exercise of the book Accelerated C++, but I'm getting these errors and I can't figure out how to fix them:

C:\MinGW\bin..\lib\gcc\mingw32\3.4.2........\include\c++\3.4.2\bits\allocator.h||undefined reference to `vec::create()'|

::~vec()]+0x43):C:\MinGW\bin..\lib\gcc\mingw32\3.4.2........\include\c++\3.4.2\bits\allocator.h||undefined reference to `vec::uncreate()'|

I'm using code::blocks and both files are in the same project, so I'm pretty sure it's not a linking issue.

Here is the vec.h file

#ifndef VEC_H
#define VEC_H

#include <cstddef>
#include <memory>

template <class T> class vec{
public:
    typedef T* iterator;
    typedef const T* const_iterator;
    typedef size_t size_type;
    typedef T value_type;

    vec(){
        create();
    }

    explicit vec(size_type n, const T& val = T()){
        create(n,val);
    }

    vec(const vec& v){
        create(v.begin(), v.end());
    }

    ~vec(){
        uncreate();
    }

    size_type size() const{
        return avail - data;
    }

    T& operator[](size_type i){
        return data[i];
    }

    const T& operator[](size_type i) const{
        return data[i];
    }

    vec& operator = (const vec&);

    void push_back(const T& t){
        if(avail == limit)
            grow();
        unchecked_append(t);
    }

    iterator begin(){ return data; }
    const_iterator begin() const{ return data; }

    iterator end(){ return avail; }
    const_iterator end() const{ return avail; }

private:
    iterator data; //first element
    iterator avail;//one past the last available element
    iterator limit;//one past the total allocated memory

    //facilities for memory allocation

    std::allocator<T> alloc; //object to handle memory allocation

    //allocate and initialize the underlying array
    void create();
    void create(size_type, const T&);
    void create(const_iterator, const_iterator);

    //destroy the elements in the array and free the memory
    void uncreate();

    //support functions for push_back
    void grow();
    void unchecked_append(const T&);
};

#endif // VEC_H

and the vec.cpp file

#include "vec.h"

template <class T> vec<T>& vec<T>::operator=(const vec& rhs){
    //check for self-assignment
    if(&rhs != this){
        //free the array in the left-hand side
        uncreate();

        //copy elements from the right-hand to the left-hand side
        create(rhs.begin(), rhs.end());
    }

    return *this;
}

template <class T> void vec<T>::create(){
    data = avail = limit = 0;
}

template <class T> void vec<T>::create(size_type n, const T& val){
    data = alloc.allocate(n);
    limit = avail = data+n;
    uninitialized_fill(data, limit, val);
}

template <class T> void vec<T>::create(const_iterator i, const_iterator j){
    data = alloc.allocate(j-i);
    limit = avail = uninitialized_copy(i, j, data);
}

template <class T> void vec<T>::uncreate(){
    if(data){
        //destroy in reverse order the objects that were constructed
        iterator it = avail;
        while(it != data)
            destroy(--it);

        //return all the space that was allocated
        alloc.deallocate(data, limit-data);
    }

    data = limit = avail = 0;
}

template <class T> void vec<T>::grow(){
    //when growing, allocate twice as much space as currently in use
    size_type new_size = max(2*(limit-data), ptrdiff_t(1));

    //allocate new space and copy existing elements to the new space
    iterator new_data  = alloc.allocate(new_size);
    iterator new_avail = uninitialized_copy(data, avail, new_data);

    //return the old space
    uncreate();

    //reset pointers to point to the newly allocated space
    data  = new_data;
    avail = new_avail;
    limit = data + new_size;
}

//assumes avail points to allocated, but uninitialized space
template <class T> void vec<T>::unchecked_append(const T& val){
    alloc.construct(avail++, val);
}

What am I doing wrong ?

Koz
  • 151
  • 2
  • 14

2 Answers2

1

Since your class is a template you need to put the implementation into the header file, not in a .cpp file as the full class definition needs to be visible to the compiler during compilation.

Sean
  • 60,939
  • 11
  • 97
  • 136
0

Templates must be defined in every translation unit that uses them; by putting the function definitions into a source file, they are only defined in one unit, giving errors if you try to use them in another.

Move the function definitions into the header, after the class definition.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644