0

So i have a custom made vector class with also an custom allocator:

#define _SCL_SECURE_NO_WARNINGS

#include <iostream>
#include <exception>
#include <sstream>
#include <string>
#include <iostream>

namespace mem {
    template<typename T>
    class allocator {
    public:
        //
        T * allocate(int n);                    //allocate space for n objects of type T
        void deallocate(T* p);      //deallocate n objects of type T starting at p

        void construct(T* p, const T& v);   // construct a T with the value v in p
        void destroy(T* p);                 // destroy the T in p
    };

    template<typename T> T* allocator<T>::allocate(int n)                   //allocate space for n objects of type T
    {
        T* res = (T*)malloc(sizeof(T)*n);
        if (res == nullptr)
            throw std::bad_alloc();

        return res;
    }

    template<typename T> void allocator<T>::deallocate(T* p/*, int n*/)     //deallocate n objects of type T starting at p
    {
        free(p);
    }

    template<typename T> void allocator<T>::construct(T* p, const T& v)                 // construct a T with the value v in p
    {
        new(p) T(v);
    }

    template<typename T> void allocator<T>::destroy(T* p)                   // destroy the T in p
    {
        p->~T();
    }
}

namespace vec {
    template<typename T, typename A = mem::allocator<T>>
    class vector {
        A alloc;        //use allocate to handle memory for elements
        int sz;         //the size
        T* elem;        //a pointer to the elements
        int space;      //size + free space
    public:
        using size_type = unsigned long;
        using value_type = T;
        using iterator = T * ;
        using const_iterator = const T*;

        vector() :sz{ 0 }, elem{ nullptr }, space{ 0 } {}
        explicit vector(int s) :sz{ s }, elem{ new T[s] }, space{ s }
        {
            for (int i = 0; i < sz; ++i) elem[i] = 0;           // elements are initalized
        }

        vector(const vector& arg);                              //copy constructor
        vector& operator =(const vector& a);                    //copy assignment

        vector(vector&& a);                                     //move constructor
        vector& operator=(vector&& a);                          //move assignment

        ~vector() { delete[] elem; }                            //destructor

        void reserve(int newalloc);
        void resize(int newsize, T val = T());                              //growth
        void push_back(const T& val);

        iterator begin() { return elem; }
        const_iterator begin()const { return elem; }
        iterator end() { return elem + sz; }
        const_iterator end() const { return elem + sz; }
        size_type size() { return sz; }

        iterator back() { return end() - 1; }
        const_iterator back() const { return end() - 1; }

    };

    template<typename T, typename A> vector<T, A>::vector(const vector<T, A>& a)                    //copy constructor
        :sz{ a.sz }, elem{ new T[a.sz] }
    {
        copy(a.elem, a.elem + sz, elem);
    }

    template<typename T, typename A> vector<T, A>& vector<T, A>::operator =(const vector<T, A>& a)  //copy assignment
    {
        if (this == &a) return *this;           //return if self assignment

        if (a.sz <= space) {                    //enough space no need for new allocation
            for (int i = 0; i < a.sz; ++i)      //copy elements
                alloc.construct(&elem[i], a.elem[i]);
            sz = a.sz;
            return *this;
        }

        T* p = alloc.allocate(a.sz);//allocate new size
        for (int i = 0; i < a.sz; ++i)  //copy elements
            alloc.construct(&p[i], a.elem[i]);
        for (int i = 0; i < sz; ++i)
            alloc.destroy(&elem[i]);            //destroy
        alloc.deallocate(elem);
        space = sz = a.sz;              //set new size
        elem = p;                       //set new elements
        return *this;                   //return a self reference
    }

    template<typename T, typename A> vector<T, A>::vector(vector<T, A>&& a)     //move constructor
        :sz{ a.sz }, elem{ a.elem }
    {
        a.sz = 0;                           //make a the empty vector
        a.elem = nullptr;
    }

    template<typename T, typename A> vector<T, A>& vector<T, A>::operator=(vector<T, A>&& a)            //move assignment
    {
        delete[] elem;                  //deallocate old space
        elem = a.elem;                  //copy a's elem and sz
        sz = a.sz;
        a.elem = nullptr;               //make a the empty vector
        a.sz = 0;
        return *this;
    }

    template<typename T, typename A> void vector<T, A>::reserve(int newalloc)
    {
        if (newalloc <= space) return;      //never decrease allocation
        T* p = alloc.allocate(newalloc);        //alocate new space
        for (int i = 0; i < sz; ++i)
            alloc.construct(&p[i], elem[i]);    //copy
        for (int i = 0; i < sz; ++i)
            alloc.destroy(&elem[i]);            //destroy
        alloc.deallocate(elem/*, space*/);          //deallocate old space
        elem = p;
        space = newalloc;
    }

    template<typename T, typename A> void vector<T, A>::push_back(const T& val)
    {
        if (space == 0)
            reserve(8);
        else if (space == sz)
            reserve(2 * space);
        alloc.construct(&elem[sz], val);    //add val at the end
        ++sz;
    }

    template<typename T, typename A> void vector<T, A>::resize(int newsize, T val)
    {
        reserve(newsize);
        for (int i = sz; i < newsize; ++i)
            alloc.construct(&elem[i], val);     //construct
        for (int i = newsize; i < sz; ++i)
            alloc.destroy(&elem[i]);            //destroy
        sz = newsize;
    }

    template<typename T, typename A> std::ostream& operator<<(std::ostream& os, const vector<T, A>& obj) //requires Element<T> && Allocator<A>
    {
        for (const auto& x : obj)
            os << x << ' ';
        os << '\n';
        return os;
    }

    template<typename T, typename A> std::istream& operator>>(std::istream& is, vector<T, A>& obj)
    {
        std::string line;
        std::getline(is, line);
        if (is.bad() || is.fail())
            return is;

        std::istringstream istr{ line };
        vector<T, A> tmp;

        while (true) {
            T tmp_in = T();
            istr >> tmp_in;
            if (istr.fail()) {
                istr.clear();
                std::string invalid;
                istr >> invalid;
                continue;
            }
            tmp.push_back(tmp_in);
            if (istr.eof())break;
        }

        for (const auto& x : tmp)
            obj.push_back(x);
        return is;                      //its sends me to xutility in this step
    }
}


int main()
{
    //vec::vector <int> test;       //input "1 2 3 4 5" works fine with cin >>test
    vec::vector <std::string> test;  //input "this is a test"  breaks into xutility

    while (true) {
        std::cin >> test;           //breaks into xutility
        std::cout << test << '\n';
    }
}

Now the following problem. I can read in vector values if the vector is vector. So adding 1 2 3 4 5 is no problem. Also vector works fine. If i change the container type to vector and read in "hello this is a test" via cin >> test; I get a crahs in xutility.h:

        // MEMBER FUNCTIONS FOR _Container_base12
inline void _Container_base12::_Orphan_all() _NOEXCEPT
    {   // orphan all iterators
 #if _ITERATOR_DEBUG_LEVEL == 2
    if (_Myproxy != 0)               //It points on this line
        {   // proxy allocated, drain it
        _Lockit _Lock(_LOCK_DEBUG);

        for (_Iterator_base12 **_Pnext = &_Myproxy->_Myfirstiter;
            *_Pnext != 0; *_Pnext = (*_Pnext)->_Mynextiter)
            (*_Pnext)->_Myproxy = 0;
        _Myproxy->_Myfirstiter = 0;
        }
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */
    }

Visual Studio 2017 throws: Exception thrown: read access violation.this was 0xC83FB858.

How can this header even get called and what is the meaning of it? I really have no idea whats going on.

I replaced the custom vector with std::vector and then it also works.

edit: I minimized the code a bit and added a namespace for the vector. still the same behavior:

vec::vector<int> test;
std::cin >> test;       //Ok: Example input 1 2 3 4 5

vec::vector<std::string> test;
std::cin >> test;       //Mem access violation in xutility: Example input "this is a test"
Sandro4912
  • 313
  • 1
  • 9
  • 29
  • 3
    Please read [Why is “using namespace std” considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) and think about using namespaces yourself. And pray that none of the system header files you include also include the system `` header file. – Some programmer dude Feb 26 '18 at 14:46
  • 1
    This may not compile, because of the name clash between your global `::vector` and `std::vector`. Please provide a [MCVE](https://stackoverflow.com/help/mcve). – Walter Feb 26 '18 at 14:51
  • i shortened the example above a bit and added the namespace for the vector – Sandro4912 Feb 26 '18 at 15:21

1 Answers1

0

The application crashes because:

  1. The code does not use allocator consistently and ends up doing free() on memory that was allocated with new[].
  2. The code does not maintain vector::space variable consistently.
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • i replaced all new / delete with alloc.allocate / alloc.deallocate and now it seems like it works. what do you mean with ´vector::space´ is not used consitently? – Sandro4912 Feb 26 '18 at 17:55
  • @Sandro4912 For example, `vector(const vector& a)` constructor leaves it uninitialized. – Maxim Egorushkin Feb 26 '18 at 18:00
  • thanks for the advice. i did this vector based on the Book PPP by B.Stroustrup. It developed the vector in stages. first there was no space member introduced. Later it got introduced but it wasnt mentioned to check all the constructors etc again to iniatalize it. – Sandro4912 Feb 26 '18 at 23:01