Hacker News new | ask | show | jobs
by soulbadguy 1037 days ago
> The former is because meaningfully using smart pointers (i.e. letting them handle destruction) inside an allocator aware data structure (as many C++ data structures tend to be, and even data structures in Rust) would require duplicating the allocator over and over.

Not quite clear what duplicating means here, but in general most smart_pointers can be constructed with an optional "deleter". Well implmented this would results into the addition one reference (64 bits) field to each instance of the smart_pointer (remove that by using some static member kung-fu but this is hardly worth it).

> The latter is because compilers do not perform TCO in many real world examples (and certainly not in debug mode); if you write a linked list using `std::unique_ptr` the destructor will blow your stack.

This true for all deeply nested structure. Same thing happen in reference counted system like swift. One can mitigate this by simply controlling the order of destruction.

1 comments

Duplicating meaning that the smart pointer deleter is going to need a copy of the allocator (or a pointer to it if you prefer, but allocators are already typically pointers). If your container is storing N separately allocated elements, holding them by unique_ptr instead of raw pointer will waste N pointers worth of space with commensurate extra cache use. Fine for homework but not production data structures.

If you control the order of destruction, then you're just manually asking for things to be destroyed, and not actually making use of the smart pointers main functionality. Why use them at that point? That's why I also used the phrase "meaningfully" use them earlier.

Look inside the STL, boost, abseil, etc. You'll very rarely see smart pointers used to implement containers/data structures.

You changed your focus from general data structure to containers specifically which have indeed differents (eg more specialized) design constraints. But still...

> If your container is storing N separately allocated elements, holding them by unique_ptr instead of raw pointer will waste N pointers worth of space with commensurate extra cache use. Fine for homework but not production data structures.

Designing a data structure is an exercise in compromise. You lose space/cache efficiency and gain (exception) safety and ease of use. And of course the lost of space/cache efficiency is a function of both the usage pattern and the size of the store elements... Calling it "fine for home work" is needlessly dismissive.

> If you control the order of destruction, then you're just manually asking for things to be destroyed, and not actually making use of the smart pointers main functionality.

I disagree with the premise that the main functionally of smart pointers is automatic destruction. Exception safety and ease of use seems more important to me. So using smart_pointer and still controlling the order of destruction is a perfectly valid use case.

But an even more important point is that smart_pointer are designed in way that the length of the management can be different from the life time of resource being managed; By using the reset/release/construct_from_pointer methods. And indeed there are multiple designs when a resource is created unmanaged, then attached to a smart_pointer for a while, then returned to an unmanaged state.

This reflects the fact that the same resource can have different management needs depending on where in the program one is.

> Look inside the STL, boost, abseil, etc. You'll very rarely see smart pointers used to implement containers/data structures.

It doesn't imply any fault in the design of smart pointers. Smart pointers are resource lifetime management tools, STL containers in general have very simple lifetime contracts... There is simply no need to use them.