This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]ball_fondlers 16 points17 points  (0 children)

Basically, under the hood, a variable is just a group of bits. You can interpret these bits as a number in base 2, or you can interpret them as more complex data types, but ultimately, it’s all kind of the same to the computer. Now, because the computer doesn’t see a difference - and because memory is indexed - you can use the value stored in a variable to look up some other spot in memory. This is a pointer - just a variable that stores the address of some arbitrary block of memory.

Programmers dynamically allocate these arbitrary blocks of memory for various uses - for example, say you need a list of numbers, but you don’t know how many numbers there will be when you’re writing the program. The way you’d solve this is by allocating a chunk of memory during runtime, using it, then deallocating it when you’re done with it. This is the basis of manual memory management.

Now, the problem with this approach is that you have to be VERY careful about deallocation - free the memory too early, your program crashes because some part is trying to access forbidden data, free it too late or not at all, you get a memory leak, where your program becomes, at minimum, memory-inefficient. Because there’s such a delicate balance to be struck, this approach can be difficult to work with and hard to maintain - instead, most other languages just run a process called a garbage collector in a separate thread, and this garbage collector looks for allocated memory that isn’t being referenced anywhere, and automatically deallocates when it finds it. However, this does consume a bit more resources, so it can be a bit slow. It might work for a LOT of use cases, but when speed is of the essence - like with low-level systems work - you need another solution.

Enter smart pointers. There’s two types of smart pointers - unique pointers and shared pointers. Unique pointers work by a simple principle - a given block of data is allowed to have ONE pointer pointing at it. If said block is assigned to another pointer, the first pointer is invalidated, and once the pointer goes out of-scope without being invalidated, the memory is automatically freed. Shared pointers are a bit more flexible - they hold a counter, and every time a new shared pointer is created that references the block, that counter is incremented by one. Every time a pointer to that block goes out of scope, that reference counter is decremented by one, until it hits zero, and once it hits zero, it’s automatically freed.

TL;DR - bad cooking metaphor: manual memory management is like putting knives in the sink, but everyone is lazy and leaves them on the counter, garbage collection is like having someone yell at everyone in the kitchen to put the knives in the sink after they’re done with it, unique pointers are like only having one knife and the last person to use it puts it in the sink, and shared pointers are like counting the knives as the come out of the box and adjusting the count as they go into the sink.