--- Comment #30 from Andrei Alexandrescu <and...@erdani.com> ---
Indeed it seems we are not supporting registration by address with ease for D
There are good reasons for that; by allowing value types to be moved around we
avoid a swath of complications and difficulties that C++ encounters with their
definition of rvalue references and move constructors. That C++ feature
complicates all code considerably and still has a variety of safety,
correctness, and efficiency issues (I am not exaggerating; all three problems
are present) that make the bread and butter of advanced C++ instructors
worldwide, including myself. I think we got the better deal there.
The disadvantage is that indeed an object can be born and die at different
addresses. So self-registering objects by address, or objects holding internal
pointers, do not work with automatic allocation. Such is the nature of
automatic allocation in D.
(It should be noted that C++ has its own, distinct issues with self-registering
objects, to which I dedicate several slides in
Allow me to make a few suggestions for workarounds:
* Avoid automatic/stack allocation and also return by value. A struct may hold
internal pointers and a constant address as long as the memory it's in is not
automatic/stack. If you use raw memory in conjunction with functions such as
emplace and destroy, you have good control. As a perk, you avoid the creation,
copying, and destruction of spurious objects - which comes along with calls to
register/unregister, which I assume has a significant cost.
* Use a "cookie", not an address, in the registration. A classic registration
pattern returns a cookie/handle, usually an integer, which the object stores.
Then, the object passes that cookie back to the unregister function. In other
words, if the address of an object isn't invariant, let's define something that
* Use dynamic allocation in conjunction with reference counting. I know this
has been mentioned and dismissed as too expensive, but I'm mentioning it for
completeness. Also, it's one of those cases in which engineering can go a long
way: use a high-performance allocator (for which we have a solid framework in
the standard library), duplicate objects lazily, etc.
If after exploring these and other solutions you come to the conclusion they
are not satisfactory, I encourage you to create a DIP. Two possible lines of
(1) Allow specifying that an object can't be moved
(2) Allow a type to intercept its move by means of a nothrow hook
Drawing from extensive experience with Phobos and its very generic code, I can
tell you I foresee difficulties with (1). Anything that makes types "more
special than others" is bound to cause a smorgasbord of special handling in the
library. I think (2) would be a better angle because it encapsulates the
handling with the type.