Boost logo

Boost :

Subject: Re: [boost] [smart_ptr] Interest in the missing smart pointer (that can target the stack)
From: Noah (duneroadrunner_at_[hidden])
Date: 2016-01-29 13:53:54


On 1/28/2016 5:07 PM, Nat Goodspeed wrote:
> Do you mean, for example, that you can create a registered_ptr to an
> instance within the constructor? (I haven't looked at your
> implementation.)

So first, let me say that I am by no means a C++ (or boost or stl) expert.

If I understand your question, the short answer is yes, sort of.

But there's a longer answer. You are asking if a registered_ptr can
replace the raw pointer in this scenario?:

class CA {
public:
     CA() {
         m_ptr_to_this = this;
     }
     CA* m_ptr_to_this;
};
CA a_obj;

I actually have two implementations - one called TRegisteredPointer and
one called TRegisteredPointerForLegacy. TRegisteredPointerForLegacy is a
little slower, but more "lenient" / less "strict" / more compatible with
raw pointers. With TRegisteredPointerForLegacy, this is no problem:

class CA {
public:
     CA() {
         m_ptr_to_this = this;
     }
     mse::TRegisteredPointerForLegacy<CA> m_ptr_to_this;
};
mse::TRegisteredObjForLegacy<CA> a_obj;

My implementation of TRegisteredPointer is more strict than
TRegisteredPointerForLegacy and doesn't (currently) support this. The
two implementations represent different tradeoffs between speed & safety
and compatibility & flexibility.

>> my implementation can only target
>> types that can act as base classes. By default most classes can act as a
>> base class, but native types like int, bool, etc. cannot.
>
> That could be a bigger problem than it appears, given 'final' classes.

Umm, yes maybe. Personally, I never use 'final' classes, so my
implementation currently uses the target object as a base class. But it
could be (and probably will be) extended to also support the target
object as the derived class instead. This is the way "QPointer" works if
you're familiar with Qt. Basically we need a certain function to be
called when the target object is destructed and we don't really care how
it's done. We can add a destructor by deriving a new class from the
target class, or we can add a destructor by having the target class be
derived from a specific class, or frankly, the appropriate code can be
manually inserted into the existing destructor of the target class.
Either way will work. Using the target class as a base class is just the
"cleanest", least "intrusive" of the options.

It's true, it doesn't seem that this kind of pointer can be implemented
in a way that's as "universal" as, say std::shared_ptr. And maybe that's
why boost doesn't already include something like it. But is that
sufficient reason to forego the real functional benefits of this kind of
pointer?

> Um... I'm not sure people would regard use of those substitutes as an
> acceptable requirement for working with registered_ptr.

Yeah, another shortcoming I would've liked to have avoided if there was
some way to do so. But to be clear, you only need to use the substitutes
if you're pointing directly at a primitive type. Pointing to a class
that contains primitive types is not an issue. How often do people
declare a pointer to a single int? I don't think I can remember the last
time I did. But maybe that's just me.

But anyway, I'm kind of taking a stand on this particular issue, and I
invite boost, and the wider C++ community to join me. int, unsigned int,
and the other primitives are a legacy inherited from C. A bad (and
unnecessarily dangerous) legacy that needs to be tossed, in my opinion.
To be clear, registered_ptr doesn't require using *my* substitutes when
pointing to primitive types. Presumably any substitute that can act as a
base class would work just as well. The substitutes I provide are such a
thin wrapper that I assume any respectable compiler should generate the
exact same machine code (in release mode) when used as a direct
substitute for their native counterparts. But my substitutes are safer
in that they have default initialization. And they also address the bug
prone implicit conversion between signed and unsigned ints. I'm not
against using native primitives in all cases but, in my opinion, they
shouldn't still be the default.

>
>> Of course the ideal would be smart pointers that could distinguish between
>> stack allocated objects and heap allocated objects. Unfortunately, as far as
>> I know, (standard) C++ doesn't seem to give us that facility.
>
> Heh. I've wished for some time for the ability to constrain a class:
> "this cannot be static" or "this cannot be instantiated on the stack"
> or "this cannot be instantiated on the heap." But I've never been
> sufficiently motivated to write a proposal -- or, come to that, search
> through WG21 archives for an existing proposal.
>
> A good language facility that addressed my use case should also
> address yours, of course.

I haven't had time to investigate it, but I came across this project:
https://github.com/crdelozier/ironclad/. It seems to be abandoned, but
from what I could tell, it used platform specific code to determine if a
pointer was pointing to the stack or not.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk