Home > Net >  confusions about a simple smart pointer implementaion
confusions about a simple smart pointer implementaion

Time:07-10

The following code is abstracted from the book << C Hands on design patterns>>.

Some confusions have been bugging me for weeks.

(1) How the char array mem_ is initialized?

(2) Is allocate used to allocate memory? How?

(3) Why does mem_ == p ? How was the memory delocated?

// 02_scoped_ptr.C
// Version 01 with deletion policy.
#include <cstdlib>
#include <cassert>
#include <iostream>

template <typename T, typename DeletionPolicy> 
class SmartPtr {              
public:

    explicit SmartPtr(T* p = nullptr,
                      const DeletionPolicy& deletion_policy = DeletionPolicy() ) 
    : p_(p), deletion_policy_(deletion_policy) {} 

    SmartPtr(const SmartPtr&) = delete;

    SmartPtr& operator=(const SmartPtr&) = delete;

    ~SmartPtr() { deletion_policy_(p_); }                        

    void release() { p_ = NULL; }

    T* operator->() { return p_; }

    const T* operator->() const { return p_; }

    T& operator*() { return *p_; }

    const T& operator*() const { return *p_; }

private:
    T* p_;                           
    DeletionPolicy deletion_policy_;
                                    
};


class SmallHeap {
public:
    SmallHeap() {}

    SmallHeap(const SmallHeap &) = delete;

    SmallHeap &operator=(const SmallHeap &) = delete;

    ~SmallHeap() {}

    void * allocate(size_t s) {
        assert(s <= size_);
        return mem_;       // ------------------ is allocate used to allocate memory? how?
    }

    void deallocate(void *p) {
        assert(mem_ == p); // ------------------- why does mem_ == p ? How was the memory delocated?
    }

private:
    static constexpr size_t size_ = 1024;
    char mem_[size_];      // ------------------- how mem_ is initialized?
    
};

void * operator new(size_t s, SmallHeap *h) 
{ 
    return h->allocate(s); 
}

template<typename T>
struct DeleteSmallHeap {
    explicit DeleteSmallHeap(SmallHeap &heap)
            : heap_(heap) {}

    void operator()(T *p) const {
        p->~T();
        heap_.deallocate(p);
    }

private:
    SmallHeap &heap_;
};


int main() {
        SmallHeap a_sh_obj;
        SmartPtr<int, DeleteSmallHeap<int>> sh_sp{new(&a_sh_obj) int(42), DeleteSmallHeap<int>(a_sh_obj)};
        std::cout << *sh_sp << std::endl;
}


CodePudding user response:

This code demonstrates a custom allocator which has a static fixed size of size (1024). There is no allocation, but it can be used as an allocator on a STL container on the assumption that you will never need more than 1024 bytes.

If you do need more, boom.

 char mem_[size_];      

This line initializes the static size and allocate() simply returns that without any call to new.

For the deallocation it uses a simple assert to ensure that the memory that is to be 'deleted' is the same than the one that was 'created'.

All these practises are practically non existant. If you do need a vector of a static size, use a std::array. If you need a vector of an unknown size, use the reserve() vector function to preallocate. If your vector's size is unknown but expected to be small, it's okay to leave it as it is for, in Windows (and I assume in other OSes), it eventually calls HeapAlloc and HeapFree which, for small allocations, are probably cheap, especially if the vector is within a limited scope.

If you need some flexible combination of stack/heap vector, you can use https://github.com/thelink2012/SmallVector.

CodePudding user response:

How the char array mem_ is initialized?

mem_ is not initialized as in filled with values until the use of the custom new operator in new(&a_sh_obj) int(42). This only initializes a small portion of the memory though. Space is allocated on the stack however when you create the local SmallHeap a_sh_obj; variable in main.

Is allocate used to allocate memory? How?

Yes, it is used. The expression new(&a_sh_obj) int(42) uses

void * operator new(size_t s, SmallHeap *h) 
{ 
    return h->allocate(s); 
}

which gets sizeof(int) passed as first parameter and &a_sh_obj as second parameter.

Why does mem_ == p? How was the memory delocated?

On destruction of sh_sp the DeleteSmallHeap<int> object is used to get rid of the object. The assert is just verification that the memory "freed" is actually the one expected. This doesn't actually deallocate anything, since the memory is still owned by a_sh_obj. It's leaving the main function that in fact releases the memory during when cleaning up a_sh_obj.

  • Related