views:

79

answers:

1

Why in this code (this is just working code and not fully exception safe) I'm getting an assertion error:
HEAP_CORRUPTION_DETECTED ...

class Allocator
{

public:

    explicit Allocator()
    {
        std::cout << "Allocator()" << '\n';
    }

    virtual ~Allocator()
    {

        std::cout << "~Allocator()" << '\n';
    }

    template<class T>
    T* Allocate(const std::size_t count)
    {
        return static_cast<T*>(::operator new(count));
    }

    /*[nothrow]*/
    template<class T>
    void Construct(void* where_, const T& what)
    {
        new (where_) T(what);
    }

    template<class T>
    void Destruct(T* where_)
    {
        where_->~T();
    }

    template<class FwdIter>
    void Destruct(FwdIter first, FwdIter last)
    {
        while (first != last)
        {
            this->Destruct(&*first);
            ++first;
        }
    }

    template<class T>
    void Deallocate(T* where_)
    {
        ::operator delete(where_);
    }
};


template<class T>
class ToyImplementation
{
private:

public:
    typedef T value_type;
    T* data_;///move to private
    std::size_t size_;
    std::size_t capacity_;
    explicit ToyImplementation(Allocator& alloc, const std::size_t count):data_(alloc.Allocate<value_type>(count)),size_(0),capacity_(count)
    {
        std::cout << "ToyImplementation()" << '\n';
        //throw std::exception();
    }
    ~ToyImplementation()
    {
        std::cout << "~ToyImplementation()" << '\n';
    }
};


template<class T>
class ToyA
{
private:
    ToyImplementation<T>* implementation_;
    typedef ToyImplementation<T> value_type;
    Allocator alloc_;
public:
    explicit ToyA(const std::size_t count = 0): implementation_(alloc_.Allocate<value_type>(sizeof(value_type)))
    {
        alloc_.Construct(implementation_, value_type(alloc_,count));
        alloc_.Deallocate(implementation_);//<<--------HERE ERROR IS TRIGGERED
        std::cout << "Toy()" << '\n';
    }
    ~ToyA()
    {
        std::cout << "~Toy()" << '\n';
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    ToyA<int> t(10);
    return 0;
}

Seven lines up is a line which causes an error. Line is marked <<--------HERE ERROR IS TRIGGERED
Thank you.

+5  A: 

You corrupted your heap because your allocation is incorrect. Namely, consider this:

template<class T>
T* Allocate(const std::size_t count)
{
    return static_cast<T*>(::operator new(count));
}

If count is one, you get one byte. (You then try to construct an object which has a size greater than one in that memory...boom.)

You probably want:

template<class T>
T* Allocate(const std::size_t count)
{
    return static_cast<T*>(::operator new(sizeof(T) * count));
}

Note your function design is a bit unorthodox. The allocation and deallocation functions should strictly allocate and deallocate (no casts!), like this:

template<class T>
void* Allocate(const std::size_t count)
{
    return ::operator new(sizeof(T) * count);
}

void Deallocate(void* where_)
{
    ::operator delete(where_);
}

And your construction and destruction functions should be the ones that construct and return an object, and destruct an object:

template<class T>
T* Construct(void* where_, const T& what)
{
    return new (where_) T(what);
}
GMan
@GMan that's great.Thank you for mentioning functions desing. Thanks man! I mean thanks GMan!
There is nothing we can do
@GMan one problem with your answer though. It's about unorthodox design of my functions, well I've checked with microsoft et al and return types in their functions signatures were identical with mine so I think you've made... ahem... a mistake.
There is nothing we can do
@A-ha: I'm not sure I follow.
GMan
@GMan: I wouldn't say it was unorthodox to return `T*` rather than `void*`. After all, that's what `std::allocator` does.
Mike Seymour