• Some users have recently had their accounts hijacked. It seems that the now defunct EVGA forums might have compromised your password there and seems many are using the same PW here. We would suggest you UPDATE YOUR PASSWORD and TURN ON 2FA for your account here to further secure it. None of the compromised accounts had 2FA turned on.
    Once you have enabled 2FA, your account will be updated soon to show a badge, letting other members know that you use 2FA to protect your account. This should be beneficial for everyone that uses FSFT.

C++: Creating a templated smart pointer featuring operator overloading

Tower

Gawd
Joined
Oct 11, 2001
Messages
840
I've been dabbling with C++ for a few months, including templates, smart pointers, and operator overloading. As a neat project for additional education, I thought it'd be fun to create my own smart pointer, aside from (deprecated auto_ptr) and current unique_ptr.

Behold: uber_ptr. :p

As I've never written a templated class before, and I've never created a smart pointer, nor have I ever tried implementing operating overload, this is fairly intriguing.

My guess is that if you're reading this post here on [H], you're either intrigued as well, amused, or you think I'm an idiot. :)

Initial goals:
  1. Work with any type of pointer (hence, templated)
  2. Accept a void pointer in the Constructor
  3. Overload the unary "!" operator as a check for null, so that !<ptr> would return true if null.

Here's what I have so far:

uber_ptr.h

Code:
#ifndef UBER_PTR_H
#define UBER_PTR_H

template<class T> class uber_ptr
{
private:
	T * ptr;
	
public:
	// Constructors.
	uber_ptr(void);
	uber_ptr(void *);
	uber_ptr(T);

	// Overloaded Operators.
	bool operator ! ();

	// Destructor.
	~uber_ptr(void);
};

#endif

uber_ptr.cpp

Code:
#include "uber_ptr.h"

template<class T> uber_ptr<T>::uber_ptr(void)
{
	this->ptr = 0;
}

template<class T> uber_ptr<T>::uber_ptr(void * x)
{
	this->ptr = x;
}

template<class T> uber_ptr<T>::uber_ptr(T x)
{
	this->ptr = &x;
}

template<class T> bool uber_ptr<T>::operator ! ()
{
	if (this->ptr == 0)
		return true;
}

template<class T> uber_ptr<T>::~uber_ptr(void)
{
}

main.cpp

Code:
#include <windows.h>
#include "uber_ptr.h"

int main()
{
	int a = 1;
	int b = 2;

	uber_ptr<int> x (a);

	return ERROR_SUCCESS;
}

This code builds, but will not link, citing two unresolved external errors:
Error 2 error LNK2019: unresolved external symbol "public: __thiscall uber_ptr<int>::uber_ptr<int>(int)" (??0?$uber_ptr@H@@QAE@H@Z) referenced in function _main C:\Users\jshidell\Desktop\uber_ptr\uber_ptr\main.obj uber_ptr

Error 1 error LNK2019: unresolved external symbol "public: __thiscall uber_ptr<int>::~uber_ptr<int>(void)" (??1?$uber_ptr@H@@QAE@XZ) referenced in function _main C:\Users\jshidell\Desktop\uber_ptr\uber_ptr\main.obj uber_ptr

Any idea on what I'm missing? Feel free to chime in with thoughts, etc.
 
Templates cannot have accompanying cpp files, declare/define everything in the header file. Also grats on having the willpower to work on code in your free time, all programmers should do that more (myself included).
 
Thanks breaknek, that's the help I needed. Now I just need to figure out all the constructors and operators; this becomes slightly more complex when considering void constructors, copy constructors, etc. :)
 
Writing a smart pointer is actually not that difficult (to get a barebones, minimal version). Doing the operator overloads and copy constructors shouldn't be hard, but it is critical to do it correctly.

Also, you might want to take a look at your constructor with one type T parameter. I'm not so sure it's going to do what you want it to do. Additionally, look at your operator!().
 
The good ol' Proxy pattern that can be quite useful. I would recommend you build an abstract iterator as well since that is related somewhat to the same design ideas while you are doing this for fun.
 
Thanks xSnowManx, those were two items I was having trouble with. I've made some progress--see below.

SpunDucky, I'm about to read about the 'Proxy' pattern, thanks for the idea. :)

I did add an iterator of sorts, just to keep track of how many times the pointer being managed by uber_ptr is touched (int accessCount), which can be reviewed at any time by calling TimesAccessed(). Also, I thought I'd share my progress for comments (and ideas), as well as two additional questions/comments I have.

First, here's the updated code (as a single Header.) This should be portable to any standard C++ compiler. I do believe I have the Operator overloading implemented as I was shooting for; -> returns the pure pointer managed by uber_ptr, ! returns TRUE if the pointer managed by uber_ptr is NULL, and = allows for reassignment of the pointer managed by uber_ptr.

Feel free to grab this for your own use, update it, modify it, learn from it, etc. It's neat to mess around with. :)

Code:
#ifndef UBER_PTR_H
#define UBER_PTR_H

template<typename Type> class uber_ptr
{
private:

	Type * ptr;

	int accessCount;
	
public:

	//
	// Constructors.
	//

	/*uber_ptr(void)
	{
		ptr = 0;

		accessCount = 1;
	}*/

	/*uber_ptr(void * x)
	{
		ptr = x;

		accessCount = 1;
	}*/

	uber_ptr(Type x)
	{
		ptr = new Type(x);

		accessCount = 1;
	}

	//
	// Operators.
	//

	// Operator: *
	/// <summary>
	/// Returns the value of the dereferenced pure pointer managed by uber_ptr.
	/// </summary>
	Type & operator * ()
	{
		accessCount++;

		return *ptr;
	}

	// Operator: ->
	/// <summary>
	/// Returns a pure pointer of type Type (uber_ptr<Type>).
	/// </summary>
	Type * operator -> ()
	{
		accessCount++;

		return ptr;
	}

	// Operator: =
	/// <summary>
	/// Returns an uber_ptr of type Type (uber_ptr<Type>).
	/// </summary>
	uber_ptr operator = (Type x)
	{
		accessCount++;

		if (ptr == 0)
			ptr = new Type();

		ptr = &x;

		return x;
	}

	// Operator: !
	/// <summary>
	/// Returns TRUE if the pointer uber_ptr manages is NULL.
	/// Makes NULL/nullptr checks convenient with this syntax:
	///
	/// uber_ptr<Type> uPtr;
	/// if (!uPtr)
	///		Take NULL pointer action.
	/// </summary>
	bool operator ! ()
	{
		accessCount++;

		if (ptr == 0)
			return true;
		else
			return false;
	}

	// 
	// Functions.
	//

	/// <summary>
	/// Returns the number of times this uber_ptr has been accessed.
	/// </summary>
	int TimesAccessed()
	{
		return accessCount;
	}

	/// <summary>
	/// Explicitly deletes the object pointed to by the pointer managed by uber_ptr.
	/// </summary>
	/// <returns>
	/// TRUE if an object was deleted.
	/// FALSE if no object was deleted. (Managed pointer was NULL.)
	/// </returns>
	bool DeletePtr()
	{
		if (ptr != 0)
		{
			delete ptr;

			return true;
		}
		else
			return false;
	}

	/// <summary>
	/// Returns the pure pointer being managed by uber_ptr.
	/// Can be useful in certain instances; for example, compatibility with
	/// MS's VC++ "for each" statement.
	/// </summary>
	Type * GetPtr()
	{
		accessCount++;

		return ptr;
	}

	//
	// Destructor.
	//

	~uber_ptr(void)
	{
		if (ptr != 0)
			delete ptr;
	}
};

#endif

Some questions:

The default (empty) Constructor:

Code:
uber_ptr(void)
{
	ptr = 0;

	accessCount = 1;
}

If I implement this Constructor, people can define and assign an uber_ptr without assigning the pointer it manages a value. For example:

Code:
uber_ptr<int> a;

Would be a legal statement. The problem with this is that the pointer that uber_ptr manages is currently NULL. As long as the programmer is smart, they'll realize such, but if they are not, it may lead to frustration. It seems I can avoid some of that headache by simply removing the default Constructor so that it cannot be used, saving any user the headache. Thoughts?

Second, how could (or even should?) I implement a void pointer Constructor?

Code:
uber_ptr(void * x)
{
	ptr = x;

	accessCount = 1;
}

It would be nice if uber_ptr could determine what type of object the void pointer is pointing to (if it has been assigned), and then use that as it's Type. I'm just not sure that's possible. Thoughts?

What other functionality might I want to implement into a smart pointer?
 
Last edited:
Just depends on what functionality you want from it.

I would expect to treat it just like a pointer, but currently this won't compile.

Code:
#include <iostream>
#include "uber.h"

int main(void)
{
  int x = 5;
  uber_ptr<int> a = &x;
  std::cout << *a << std::endl;
}

Unless you change this constructor

Code:
typedef Type* TypeP;

uber_ptr(const TypeP& x)
{
  ptr = x;
  accessCount = 1;
}

But then it crashes when the destructor is called because it's trying to delete x. So like I said, it all depends on how you want to use it... but I would look at other implementations and check out how they're doing things and try to understand why.

I'm personally fine with managing my own memory and pointers, I run memory leak checks for both DirectX and the main code to make sure I stay on top of it early on in projects. Actually all debug/profile builds have memory leak checking enabled.

Also you can call delete or delete[] on a null pointer... "5.3.5/2 of the Standard: "In either alternative, if the value of the operand of delete is the null pointer the operation has no effect." "

This works and cleans up memory properly but probably not what you would use it for.

Code:
#include <iostream>
#include "uber.h"

int main(void)
{
  uber_ptr<int> a = new int(5);
  *a = 5;
  std::cout << *a << std::endl;
}

So it all depends on what you want from it, but there are a few semantics issues I see with what you have right now, including const related stuff. Do you want a reference counted style pointer so that you have multiple pointers to the same dynamically allocated piece of memory, and as soon as one pointer tries to modify it, it makes a copy for itself and resets the reference count to 1. And then in the destructor for all of those pointers it decrements the reference count and sees if it's zero, if so delete the pointer. There's a bit more to it, but right now I'm not sure how useful it will be for you.

Like I said though, I've never used any of these managed pointers because I never saw the need, so maybe this is what you intended.

EDIT: I realize now the first example was kind of silly, there really is no point to use this if it's not dynamically allocated. The constructor was still flawed though taking a copy of the templated type.
 
Last edited:
Some questions:

The default (empty) Constructor:

Code:
uber_ptr(void)
{
	ptr = 0;

	accessCount = 1;
}

If I implement this Constructor, people can define and assign an uber_ptr without assigning the pointer it manages a value. For example:

Code:
uber_ptr<int> a;

Would be a legal statement. The problem with this is that the pointer that uber_ptr manages is currently NULL. As long as the programmer is smart, they'll realize such, but if they are not, it may lead to frustration. It seems I can avoid some of that headache by simply removing the default Constructor so that it cannot be used, saving any user the headache. Thoughts?

It depends on how much you want to do for the user of your code. You could make your uber_ptr to be as idiotproof as possible and do lots of checks. But then you force all users to live with the overheads of your checks. Or, you could decide you want to provide minimal overhead and do less checking.

This is a design choice you'll have to make, and your interface should reflect that design choice. If your interface is inconsistent with the design goals, then that will make users frustrated.

Second, how could (or even should?) I implement a void pointer Constructor?

Code:
uber_ptr(void * x)
{
	ptr = x;

	accessCount = 1;
}

It would be nice if uber_ptr could determine what type of object the void pointer is pointing to (if it has been assigned), and then use that as it's Type. I'm just not sure that's possible. Thoughts?

I haven't run your code and I just did a brief, cursory glance, but it doesn't seem like you've implemented any semantics that a typical smart pointer provides.

Based on what I saw, you simply keep track of how many times a pointer has been accessed and nothing more. Smart pointers as provided in boost and in the standard (as of C++0x) provide various destruction semantics, but they all revolve around deleting/freeing dynamically allocated memory "automagically".

Which leads me onto your question about how to implement a void * constructor. What you're asking for isn't possible without dangerous hackery (determining the type of the object pointed to by the void pointer). If you were implementing smart pointers like those provided in boost and the standard library, then your uber_ptr would be dangerous to use. You should investigate why this is the case (requires knowing how to use the boost/std smart pointers).
 
Back
Top