lundi 26 février 2018

xutility read access violation on returning isstream with custom vector

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

alloc.h:

#ifndef ALLOC1234_GUARD
#define ALLOC1234_GUARD

namespace mem {

template<typename T>
class allocator {
public:
    //
    T* allocate(int n);                 //allocate space for n objects of type T
    void deallocate(T* p/*, int n*/);       //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();
}

}
#endif

vector.h:

#ifndef VECTOR1234_GUARD
#define VECTOR1234_GUARD

#include "alloc.h"
#include <exception>
#include <sstream>
#include <string>
#include <iostream>

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

    T& at(int n) {                                          //checked access;
        if (n < 0 || sz <= n)
            throw std::out_of_range("vector");
        return elem[n]; 
    };                                          
    const T& at(int n) const{
        if (n < 0 || sz <= n)
            throw std::out_of_range("vector");
    return elem[n];
    };

    T& operator[](int n) { return elem[n]; }                //access: return reference
    const T& operator[] (int n) const { return elem[n]; }   

    int size() const { return sz; }                         //the current size
    int capacity() const { return space; }                  

    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; }

    iterator insert(iterator p, const T&val);
    iterator erase(iterator p);
};

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>    //requires Element<T> && Allocator<A>
typename vector<T, A>::iterator vector<T, A>::erase(iterator p)
{
    if (p == end()) return p;
    for (auto pos = p + 1; pos != end(); ++pos)
        *(pos - 1) = *pos;          //copy element "one position to the left
    alloc.destroy(&*(end() - 1));   //destroy surplus copy of last element
    --sz;
    return p;
}

template<typename T, typename A>    //requires Element<T> && Allocator<A>
typename vector<T, A>::iterator vector<T, A>::insert(iterator p, const T&val)
{
    int index = p - begin();
    if (size() == capacity())
        reserve(size() == 0 ? 8 : 2 * size());  //make sure we have space
    //first copy last element in uninitalized space:
    alloc.construct(elem + sz, *back());
    ++sz;
    iterator pp = begin() + index;      //the place to put val
    for (auto pos = end() - 1; pos != pp; --pos)
        *pos = *(pos - 1);      //copy elements one position to the right;
    *(begin() + index) = val;   //insert val;
    return pp;
}

template<typename T, typename A>    //requires Element<T> && Allocator<A>
std::ostream& operator<<(std::ostream& os, const vector<T,A>& obj)
{
    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;  // it sends me to xutility.h here
}

#endif

main.cpp:

#define _SCL_SECURE_NO_WARNINGS

#include <iostream>
#include <string>
#include <exception>
#include "vector.h"
using namespace std;

inline void keep_window_open(string s)
{
    if (s == "") return;
    cin.clear();
    cin.ignore(120, '\n');
    for (;;) {
        cout << "Please enter " << s << " to exit\n";
        string ss;
        while (cin >> ss && ss != s)
            cout << "Please enter " << s << " to exit\n";
        return;
    }
}

int main()
try {


    //vector <int>test;   //this works fine
    vector <string> test;

    while (true) {
        cin >> test;
        cout << test << '\n';
    }
    keep_window_open("~");
}
catch (runtime_error& e) {
    cerr << e.what() << "\n";
    keep_window_open("~");
}
catch (out_of_range& e) {
    cerr << "out of range access " << e.what() << "\n";
    keep_window_open("~");
}
catch (bad_alloc& e) {
    cerr <<"memory alloc failed "<< e.what() << "\n";
    keep_window_open("~");
}
catch (...) {
    cerr << "unknown error " << "\n";
    keep_window_open("~");
}

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 works.

Aucun commentaire:

Enregistrer un commentaire