(Replying to PARENT post)
Rust requires types to explicitly opt-in to being implicitly copied, while C++ requires you to opt-out by deleting the copy-constructor.
Accidentally copying small structs on the stack is a minor performance problem. Copying an std::box<int> in a hot loop could cause heap fragmentation, lock contention and huge amounts of wasted memory due to heap alignment requirements (32 bytes on 64-bit arches).
(Replying to PARENT post)
No C++ smart pointer has "value semantics", relative to its target T. You can see this because == performs address comparison, not deep comparison, and `const` methods on the smart pointer can be used to mutate the target (e.g. in C++, operator* on unique_ptr is always const, and yields a T&).
This is in contrast to Rust, where Box performs deep equality, and has deep const/mut. In Rust, Box is basically just a wrapper around a value to have it on the heap (enabling things like dynamic polymorphism, like in C++). In C++, the pointer is its own entity, with its own separate equality, and so on.
Const-ness of operations, operator==, and assignment/copying behavior all have to be consistent with each other. For example, if `box` was simply `unique_ptr` with a copy constructor (somehow, and as the table in the blog post basically implies), then you would have that after `auto a = b;`, `a != b`, which obviously doesn't work. This means that the hypothetical `std::box` would have to have its comparison and const-ness adjusted as well. In C++ terms, this isn't really a pointer at all. The closest thing to what the author is suggesting is actually `polymorphic_value`, I believe, which IIRC has been proposed formally (note that it does not have pointer in the name).
Also as an aside, smart pointers are not suitable a) for building data structures in general, and b) building recursive data structures in particular. 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. 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.
(Replying to PARENT post)
(Replying to PARENT post)
I don't understand why the author writes "raw value is straightforward and efficient... However, you can't allocate them dynamically and you can't build recursive data structure such as a linked list or a tree with them." There is clearly something I don't understand here. Consider an int -- you can dynamically allocate one, you can put it in a tree. Putting a box into a tree will still require other data applicable to the tree itself, same as an int), and so on. So I don't understand the point being made here.
And the deep copy behavior is rarely what I want in a mutable structure anyway (it's always safe, if usually wasteful, in a R/O structure).
(Replying to PARENT post)
I think the underlying cause is that Rust's assignment semantic is a destructive move, not a copyβ , which frees up the opportunity for an actual copy to be potentially expensive, matching reality. In a language where assignment is copy, that operation must be cheap and so we've obliged to make up an excuse for how although this is a "copy" it doesn't behave the way you want, it's just a "shallow copy".
β Although it will nearly always work to think of Rust's assignments as destructive move, as an optimisation types whose representation is their meaning can choose to implement Copy, a trait which says to the compiler that it's fine to actually just copy my bits, I have no deeper meaning - thus if the type you're using is Copy then assignments for that type are in fact performed just by copying and don't destroy anything. So a byte, a 64-bit floating point number, a 4CC, an IP address none of those have some larger significance, they're Copy, but a string, a HashMap, some custom object you made (unless it can and did opt in to Copy), those are not Copy.
Crucially, from an understanding point of view. Implementing Copy requires a trivial implementation of Clone. As a result it feels very natural.
(Replying to PARENT post)
(Replying to PARENT post)
There is no builtin deep copy facility. Without the facility then a box pointer would be dangerous leading to weird effects when the copy is too shallow.
You could solve deep copy with a template that relies on each class providing a deep copy function if one is needed. But again, this will make bugs if someone forgets to provide the function.
Rather than make an error-prone feature in the standard library, I think it would be better to just explicitly roll this yourself. A sensible constructor copy should already do a deep copy -- or ensure copy-on-write to simulate a deep copy. So copying is as easy a calling make_shared (original) or make_unique (original).
(Replying to PARENT post)
This is pretty much impossible when holding a pointer of base class. However, this is a primary reason for having pointers in the first place (polymorphism, and having abstract base classes).
In all other cases, you're probably better off with either the raw value, std::variant or std::reference_wrapper.
(Replying to PARENT post)
so, is it the pointer that is heap-allocated or the pointee? frankly, i find this article somewhat incoherent, and importantly, it lacks code examples illustrating what it is talking about.
(Replying to PARENT post)
(Replying to PARENT post)
(Replying to PARENT post)
That doesnβt seem to fix a memory bug (cause doing this with a unique ptr, then the compiler would yell at you for using copy), it seems to just make it easier than having to write `std::make_unique(*otherptr);`
(Replying to PARENT post)
(Replying to PARENT post)
I also think the semantics of shared and unshared const and mutable state need to be made explicit. Pony is very good about this more so than Rust by bringing into the language.
(Replying to PARENT post)
(Replying to PARENT post)
virtual std::flexptr<Thing> get_expensive_thing();
vs: virtual bool has_expensive_thing();
virtual const Thing& get_expensive_thing();
virtual std::unique_ptr<Thing> build_expensive_thing();
It'd probably have shared_ptr semantics but you'd have to treat it as a const ref for lifetime purposes, which might make it distasteful to the std library folks.(Replying to PARENT post)
But I doubt many people would use it, and thatβs probably why it doesnβt belong in std::.
In contrast, before C++ 11, developers would write their own RAII-style smart pointers. So it made sense to save them the labor. I donβt think a pointer that doesnβt allow shallow copies is usually found in codebases. It sounds like a specific use-case pointer.
Itβs a neat type that people coming from other languages could like, but maybe not quite standard library-ready?
(Replying to PARENT post)
non_null_unique_ptr<T>
that is enforced at compile time would be far more valuable for me. That would mean some kind of destructive move where the compiler guarantees that you can not access a moved from object.(Replying to PARENT post)
From what i understand the key here is that authors seem to be mixing references and pointers.
What the author wants here (std::box) is a garbage collected/RAII'ed reference to a heap allocated object.
smart_pointers are pointers... which is to say their identity is distinct from pointed object.
I don't think std::box is missing as much as it doesn't really fit well in C++ current memory model, and distinction between references, pointer and ownership.
(Replying to PARENT post)
I think if you come from other languages you assume the heap is the default when it should be the exception.
(Replying to PARENT post)
The lack of this type can be viewed as a pessimization for copying objects.
(Replying to PARENT post)
Taking that aside, I agree it would make a lot of sense to write code in that style^^
(Replying to PARENT post)
(Replying to PARENT post)
In Rust you will love unless you write `Clone`.
(Replying to PARENT post)
https://hackernoon.com/value-ptr-the-missing-c-smart-pointer...
https://buckaroo.pm/blog/value-ptr-the-missing-smart-ptr
People have been writing pointer-like value semantic wrappers for type-erasure for decades.