Custom Shared Ptr

Hi, this is my first time asking a programming question on here so forgive me if you don't like my way of asking them.

Anyway, I'm writing my own version of a shared pointer to utilize my engine's allocator classes, and I'm having trouble debugging. This is my result after 20-30 minutes of writing, so forgive it's lack of comments and it's ugliness.

I keep getting a runtime-error with VS 2012 stating that I'm accessing memory that I don't own, and I swear I've tried every way of fixing it and I'm leaning toward a complete rewrite.

I'm not sure what's wrong, but I'm almost certain I'm over-looking it.

This class is encapsulated in a namespace, so forgive me if I left any artifacts behind.

I'd be grateful if someone could overlook this code and determine what's wrong with it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
template<typename T, typename A = MemoryPool>
class SharedPtr
{
	public:
		SharedPtr(T* ptr = nullptr) :
		pointer(ptr)
		{
			if(ptr == nullptr)
			{
				ref = nullptr;
				return; // Return early
			}

			ref = reinterpret_cast<size_t*>(allocator.RequestMemory(sizeof(size_t)));
			if(ref == nullptr)
			{
				pointer = nullptr;
			}

			*ref = 1;
		}

		SharedPtr(const SharedPtr<T, A> &right)
		{
			ref     = right.ref;
			pointer = right.pointer;

			*ref += 1;
		}

		~SharedPtr()
		{
			// If the reference is equal to nullptr just set the pointer to nullptr and exit early
			if(ref == nullptr)
			{
				pointer = nullptr;
				return;
			}

			// Check if this is the last reference
			if(*ref == 1)
			{
				allocator.FreeMemory(ref);
				allocator.FreeMemory(pointer);
			}

			else
				*ref -= 1;

			ref     = nullptr;
			pointer = nullptr;
		}

		SharedPtr<T, A> &operator=(const SharedPtr<T, A> &right)
		{
			// Make sure the reference memory isn't leaked
			if(ref != nullptr)
			{
				if(*ref == 1)
				{
					allocator.FreeMemory(ref);
					allocator.FreeMemory(pointer);
				}

				else
					*ref -= 1;
			}

			ref     = right.ref;
			pointer = right.pointer;

			*ref += 1;

			return *this;
		}

		bool operator==(const SharedPtr<T, A> &right)
		{
			return (pointer == right.pointer);
		}

		bool operator!=(const SharedPtr<T, A> &right)
		{
			return (pointer != right.pointer);
		}

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

	private:
		T*      pointer;
		size_t* ref;
		A       allocator;
};
I can't see anything wrong with this at first glance, although it normally makes sense to be using the standard allocators as the default (see http://www.cplusplus.com/reference/memory/allocator/ ), because most people's custom allocators will have the same function names as this allocator.

Have you tried debugging it? If you have, please give us the call stack and/or where the program encountered this error.
Yea, I tried to debug it before posting it here, but I wasn't sure of it's relevance.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
		~SharedPtr()
		{
			// If the reference is equal to nullptr just set the pointer to nullptr and exit early
			if(ref == nullptr)
			{
				pointer = nullptr;
				return;
			}

			// Check if this is the last reference
			if(*ref == 1)
			{
				allocator.FreeMemory(ref);
				allocator.FreeMemory(pointer);
			}

			else
				*ref -= 1;

			ref     = nullptr;
			pointer = nullptr;
		}
The bold line is the line that is giving me trouble. Apparently the pointer is being modified and has an invalid value.

I was planning on modelling it after the standard allocator later on in my engine's development cycle, however I just want to get something on the screen at this point.
Last edited on
> Anyway, I'm writing my own version of a shared pointer to utilize my engine's allocator classes

Consider writing a standard-library-compatible allocator wrapper over the engine's allocator.
And then using std::allocate_shared http://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared

The problem with making the allocator class a template parameter of the shared pointer is that shared pointers with different allocators are not type-compatible.

And by writing a custom shared pointer, we lose a lot of the functionality provided by the standard library.
For instance, std::weak_ptr<>. http://en.cppreference.com/w/cpp/memory/weak_ptr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <string>
#include <memory>
#include <boost/pool/pool_alloc.hpp>
#include <vector>

struct test
{
    test( std::string a = "default_a", std::string b = "default_b" ) : a(a), b(b)
    { std::cout << "test::test( '" << a << "', " << b << " ) object at: " << this << '\n' ; }

    ~test() { std::cout << "test::~test() object at: " << this << '\n' ; }

    std::string a ;
    std::string b ;
};

int main()
{
    boost::pool_allocator<test> custom_allocator ;

    std::vector< std::shared_ptr<test> > pointers = 
    {
        std::allocate_shared<test>( custom_allocator ),
        std::allocate_shared<test>( custom_allocator, "abcd" ),
        std::allocate_shared<test>( custom_allocator, "efgh", "ijkl" ),
        
        std::make_shared<test>(),
        std::make_shared<test>( "mnop" ),
        std::make_shared<test>( "qrst", "uvwx" ),
        
        std::shared_ptr<test>( new test()) ,
        std::shared_ptr<test>( new test( "yzAB" )) ,
        std::shared_ptr<test>( new test( "CDEF", "GHIJ" ))
    };
        
}

http://coliru.stacked-crooked.com/a/5a81c2e4172fb34c
Topic archived. No new replies allowed.