0

I've implemented a simple vector-like structure It works well if i use vector<int> or vector<char> but when i use <vector<vector<int>> it makes error Is there are good implementation code about vector stl or problem in my code?

here is my code

class _vector {
private:
    int _size;
    int _capacity;
    T* vc;

public:
    _vector(int size = 1) {
        _size = 0;
        _capacity = size;
        vc = new T[size];
    }
    ~_vector() {
        delete[] vc;
    }
    int size() { return _size; }
    bool empty() { return !_size; }
    void resize(int size) {
        _capacity = size;
        T* tmp = new T[size];
        for (int i = 0; i < _size; i++) tmp[i] = vc[i];
        delete[] vc;
        vc = tmp;
    }
    void clear() {
        delete[] vc;
        _capacity = 1;
        _size = 0;
        vc = new T[_capacity];
    }
    void push_back(T val) {
        if (_size == _capacity) resize(2 * _capacity);
        vc[_size++] = val;
    }
    void pop_back() {
        if (_size == 0) return;
        vc[--_size] = 0;
    }
    T& operator[](int i) const { return vc[i]; }
    _vector<T>& operator=(_vector<T> &tmp) {
        _capacity = tmp._capacity;
        _size = tmp._size;
        delete[] vc;
        vc = new T[_capacity];
        for (int i = 0; i < _size; i++) vc[i] = tmp[i];
        return *this;
    }
Jarod42
  • 203,559
  • 14
  • 181
  • 302
martin
  • 1
  • 1
  • 1) Don't begin your variable names with underscores. 2) *It works well* -- No it doesn't. If it can't work with a certain type, then there is a fundamental flaw in the code. 3) Where is your copy constructor? That is the fundamental function that is missing from your class. – PaulMcKenzie Mar 13 '19 at 02:35
  • What error does it makes? – Dmytro Dadyka Mar 13 '19 at 02:37
  • Also, how about a `main` function that shows how you are using your class? And this: `void clear()` -- Why not simply set `size` to 0? There is no need to reallocate memory. – PaulMcKenzie Mar 13 '19 at 02:39
  • thank u for ur answer. the main error is CrtlsValidHeapPointer(block) – martin Mar 13 '19 at 02:43
  • @PaulMcKenzie so u mean i don't need to clear array. just set size = 0? and also should i need to make copy constructor? – martin Mar 13 '19 at 02:44
  • @martin -- Yes. You need to implement all 3 functions (assignment operator, destructor, and copy constructor). That is called the [rule of 3](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). As to `size=0`, that is how vector is implemented when asked to be cleared. There is no need to deallocate and reallocate memory again. – PaulMcKenzie Mar 13 '19 at 02:45
  • 2
    Also, your assignment operator is not implemented correctly. But before that, just implement the copy constructor -- the assignment operator would then be trivial to implement if you use the [copy/swap idiom](https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom) – PaulMcKenzie Mar 13 '19 at 02:50
  • 2
    @PaulMcKenzie the standard vector's `clear()` is more than just setting `size=0`. It has to destruct items being removed from the internal array. This vector class needs to do the same. This is important when `T` is a non-trivial type, like, say, another vector, such as the OP is asking about in this question. – Remy Lebeau Mar 13 '19 at 03:09

1 Answers1

0

Your implementation is not following the Rule of 3, as it is missing a copy constructor, and a proper copy assignment operator (which can be implemented utilizing the copy constructor). And in C++11 and later, the Rule of 5, by adding a move constructor and a move assignment operator.

Also, your implementation does not work correctly with non-trivial types that have constructors/destructors defined, such as when T is another _vector type, or any other type that has pointers/resources allocated inside of it. So, your class needs to construct new objects when adding elements to the array, using placement-new, and destruct objects when removing elements from the array, by directly calling their destructors.

Try something more like this instead:

template <typename T>
class _vector {
public:
    typedef unsigned int size_type;
    typedef T value_type;

private:
    size_type _size;
    size_type _capacity;
    value_type* vc;

public:
    _vector(size_type initalcap = 0) : _size(0), _capacity(0), vc(0) {
        reserve(initialcap);
    }

    _vector(const _vector<T> &src) : _size(0), _capacity(0), vc(0) {
        reserve(src._capacity);
        for(size_type i = 0; i < src._size; ++i) {
            new(vc[i]) value_type(src.vc[i]);
        }
        _size = src._size;
    }

    // C++11 and later only...
    _vector(_vector<T> &&src) : _size(src._size), _capacity(src._capacity), vc(src._vc) {
        src._size = 0;
        src._capacity = 0;
        src.vc = 0;
    }

    ~_vector() {
        clear();
        delete[] reinterpret_cast<char*>(vc);
    }

    size_type size() const { return _size; }
    size_type capacity() const { return _capacity; }
    bool empty() const { return !_size; }

    void reserve(size_type newcap) {
        if (newcap <= _capacity) return;
        value_type* tmp = reinterpret_cast<value_type*>(new char[sizeof(value_type) * newcap]);
        for (size_type i = 0; i < _size; ++i) {
            new(tmp[i]) value_type(vc[i]);
        }
        delete[] reinterpret_cast<char*>(vc);
        vc = tmp;
        _capacity = newcap;
    }

    void resize(size_type newsize) {
        if (newsize < _size) {
            for(size_type i = _size; i-- > newsize; ) {
                vc[i].~value_type();
            }
            _size = newsize;
        }
        else if (newsize > _size) {
            reserve(newsize);
            for (size_type i = _size; i < newsize; ++i) {
                 new(vc[i]) value_type();
            }
            _size = newsize;
        }
    }

    void clear() {
        resize(0);
    }

    void push_back(const T &val) {
        if (_size == _capacity) reserve(2 * _capacity);
        new(vc[_size]) value_type(val);
        ++_size;
    }

    void pop_back() {
        if (_size) {
            vc[--_size].~value_type();
        }
    }

    value_type& operator[](size_type i) { return vc[i]; }
    const value_type& operator[](size_type i) const { return vc[i]; }

    _vector<T>& operator=(const _vector<T> &rhs) {
        if (&rhs != this) {
            _vector<T> tmp(rhs);
            std::swap(tmp.vc, vc);
            std::swap(tmp._size, _size);
            std::swap(tmp._capacity, _capacity);
        }
        return *this;
    }

    // C++11 and later only...
    _vector<T>& operator=(_vector<T> &&rhs) {
        _vector<T> tmp(std::move(rhs));
        std::swap(tmp.vc, vc);
        std::swap(tmp._size, _size);
        std::swap(tmp._capacity, _capacity);
        return *this;
    }
};
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I'm really appreciate for your help. I have studied algorithms without STL. So I have to practice stl implementation. – martin Mar 13 '19 at 06:44
  • 1
    @martin IMFO you need study C++ idioms 1st ( copy+swap, rule of 3/5, RAII...) as well as patterns - specifically C++ specific 1s(CRTP...). Only then start simulating some STL features. – Red.Wave Mar 14 '19 at 17:06