AlgoRythm
AlgoRythm

Reputation: 1389

char* buffer in Vector implementation

I have been browsing implementations of a vector / generalized memory management. I have found a question on codereview and I don't understand how one of the suggestions works.

Here is a snip of the relevant part of the question (the code):

template <class T>
class  Vector {
public:

    typedef T* Iterator;

    Vector();
    Vector(unsigned int size);
    Vector(unsigned int size, const T & initial);
    Vector(const Vector<T>& v);
    ~Vector();

    unsigned int capacity() const;
    unsigned int size() const;
    bool empty() const;
    Iterator begin();
    Iterator end();
    T& front();
    T& back();
    void push_back(const T& value);
    void pop_back();

    void reserve(unsigned int capacity);
    void resize(unsigned int size);

    T & operator[](unsigned int index);
    Vector<T> & operator = (const Vector<T> &);
    void clear();
private:
    unsigned int _size;
    unsigned int _capacity;
    unsigned int Log;
    T* buffer;
};

In reference to this answer, why does he recommend using a char* buffer rather than a T* buffer, and more importantly, how does this work and what does it mean? I understand that the char pointer has no initialization, but I would think that you could only use T*... how does a generic type fit into a char pointer?

Relevant part of the answer:

You are going to have a hard time making this work if the buffer is of type T. Every time you expand the buffer all the elements in the buffer will be initialized with T constructor. For int this is not a problem. But if T has a non trivial constructor then you are going to pay a heavy price initializing elements that may never be used.

T* buffer;

Really the buffer should be something that does not have a constructor.

char* buffer;

Upvotes: 0

Views: 51

Answers (1)

R Sahu
R Sahu

Reputation: 206577

The explanation is right there in the answer,

You are going to have a hard time making this work if the buffer is of type T. Every time you expand the buffer all the elements in the buffer will be initialized with T constructor. For int this is not a problem. But if T has a non trivial constructor then you are going to pay a heavy price initializing elements that may never be used.

When you can use

char* buffer_;

all the unused elements of buffer_ will contain uninitialized data but that's ok. You don't pay the price of initializing each object with a non-trivial constructor that you must pay when you use

T* buffer_;

@FrançoisAndrieux brings up anothe valid point. If T is not default constructible, you won't be able to use new T[capacity] to allocate memory.

Regarding your comment, an an array of char objects can be used to hold any object. You just have to allocate the appopriate number of char objects. Instead of capacity number of T objects, you'll have to allocate capacity*sizeof(T) number of char objects.

Upvotes: 2

Related Questions