Quote:Original post by Thunder Sky
A bit of topic but.. how is that possible? does it use some cind of preprocessing to check where the code reference to the block?
A smart pointer is not a pointer per-se, but an object. Or, if you prefer, in C terms, it's like a struct. You won't be able to pass a smart pointer where a "raw" ("naked", "dumb", "C") pointer is expected.
In C++, you can do
operator overloading. Which means that you can write foo+bar even for custom types. Overloading also extends to those operators that are required to mimic a pointer:
struct foo { int x; };class noisy_foo_pointer{private: foo* ptr;public: noisy_int_pointer(foo* p) : ptr(p) {} foo& operator*() const { puts("Derefenced!"); return *ptr; } foo* operator->() const { puts("Accessed!"); return ptr; }};
Assuming p is a valid noisy_foo_pointer, writing *p or (*p).x will cause "Dereferenced" to be printed, while writing p->x will cause "Accessed" to be printed. Note that since I haven't provided the appropriate operators, you can't do pointer arithmetic on a noisy_foo_pointer.
Now, C++ also allows your types to have
constructors (noisy_foo_pointer does have one) and
destructors which are called when a variable is created or destroyed. Along with control of the
assignment operator, this is pretty much all you need to keep track of the number of smart pointers that reference a given address -- assuming you don't try to cheat and keep dumb pointers around.
When a smart pointer is created from a dumb pointer, set the reference count to 1.
When a smart pointer is created from another smart pointer, increment the reference count -- the same counter will be shared between the two pointers.
When a smart pointer is assigned to another smart pointer, decrement the reference count of the assignment target and increment the count of the source.
When a smart pointer is destroyed, decrement the reference count.
Whenever you decrement that count, check if it reached zero. If it has, release the memory (and destroy the objects that it contained).
Finally, C++ has templates, which allow you to define your smart pointer just once and have it function (safely) for various types, instead of having to write one for ints, one for foos ... void* is rarely needed:
template<typename T>class noisy_pointer{private: T* ptr;public: noisy_pointer(T* p) : ptr(p) {} T& operator*() const { puts("Derefenced!"); return *ptr; } T* operator->() const { puts("Accessed!"); return ptr; }};typedef noisy_pointer<Foo> noisy_foo_pointer; // to emulate the previous example
Now you can use noisy_pointer<Foo>, noisy_pointer<int>, noisy_pointer<double> ...
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan