I wasn't meaning to suggest that heap allocation is not useful (e.g. the vectors I mentioned are heap allocations, as I'm sure you know), just, as you say, that C++ offers fine control over memory access patterns.
However, for shared read/writes you don't need the heap: global variables work fine, as does passing around pointers into some thread's stack. (They may not be the best practice, but it's still possible.)
Smart pointers are not just reference counting, e.g. the single owner pointer types Box (in Rust) and unique_ptr (in C++). Furthermore, the majority of the cost with many reference counting implementations is the atomic instructions required for safety, if you can get away with non-atomic instructions then the reference counting probably won't look so bad. (Rust can express a reference counted pointer that is statically restricted to a single thread `Rc`, while also providing the more expensive threadsafe one `Arc`.)
Rust is designed to offer the similar power in terms of controlling memory access patterns.
However, for shared read/writes you don't need the heap: global variables work fine, as does passing around pointers into some thread's stack. (They may not be the best practice, but it's still possible.)
Smart pointers are not just reference counting, e.g. the single owner pointer types Box (in Rust) and unique_ptr (in C++). Furthermore, the majority of the cost with many reference counting implementations is the atomic instructions required for safety, if you can get away with non-atomic instructions then the reference counting probably won't look so bad. (Rust can express a reference counted pointer that is statically restricted to a single thread `Rc`, while also providing the more expensive threadsafe one `Arc`.)
Rust is designed to offer the similar power in terms of controlling memory access patterns.