Distinguish a pointer directly created by new

150 views
Skip to first unread message

wei zhang

unread,
Aug 7, 2017, 12:37:02 AM8/7/17
to ISO C++ Standard - Future Proposals
This actually is not a proposal, I don't even know how to implement it.  But we can discuss it.
I'm always thinking a pointer that directly created by new is different from by other meanings.
A * ptr = new A();
Here we can ensure that this ptr is safer than which's retrieved by following syntax,
A* ptr = &a;
or 
A* ptr =  &(ptrB->a); which *ptrB is the structure contains A a;
or 
A* a = &a_vector[0];  here a_vector is vector<A>

The ptr directly created by new can be treated as an object's handler.  And in most cases this ptr will be valid until you call delete ptr manually or by gc_count to 0 (in shared_ptr).

Actually in some cases, we should only accept that type of ptr.  E.g. in shared_ptr<A>( A* ptr); (this example even hope you write new A() inside the parenthesis )

But the problem is how to track that information during runtime.  
1. We might use a new keyword "safe" or "unsafe" when creating that ptr (e.g. safe A * ptr = new A() ), but it requires all functions and structs use the safe syntax to accept the safe ptr even for old libs, otherwise the "safe" information will be lost after passing to the functions and structures. 
2. We could provide safe_cast<>() to convert an unknown safe ptr to safe ptr with runtime check.  So that for a ptr is safe or unsafe we need runtime support.
3. We could provide static_safe_cast<>() for an unknown safe ptr to a safe ptr, without runtime check.
4. How to treat A* ptr1 = new A() and A* ptr2 = new A[100]{} , do we treat ptr2 as safe or not?
5. char * bytes = new char [sizeof(A)];  safe A * ptr = new (bytes) A{} should be forbidden because replace new is unsafe, you will only get unsafe A * ptr = new(bytes) A{}.  I'm wondering we should make crash directly if you do so.  The only correct way is 
void * bytes = malloc(sizeof(A) );  A* ptr = new (bytes) A{}
6. struct A{B firstVar;};    A * ptr = new A();  B * ptr2 = reinterpret_cast<B*>(ptr);  safe B* ptrB = dynamic_safe_cast<B*>(ptr2).   We should get null even if ptr2 is actual B * type.
7. in delete ptr;  C runtime should check if the ptr is of safe type A.  (If with some compile flag)


I think it will be useful especially when someone want to provide a gc manager in c++ language.

inkwizyt...@gmail.com

unread,
Aug 7, 2017, 1:53:30 PM8/7/17
to ISO C++ Standard - Future Proposals

Use separate type for that. Something in line of `std::shared_ptr` or `std::unique_ptr`. You can define nearly all operation needed by you on this new type.

wei zhang

unread,
Aug 8, 2017, 3:42:36 AM8/8/17
to ISO C++ Standard - Future Proposals
What if a lib that doesn't use directly_newed_ptr?  How can I check the ptr is directly newed if I get the ptr from a lib?


在 2017年8月8日星期二 UTC+8上午1:53:30,Marcin Jaczewski写道:

d25f...@outlook.com

unread,
Aug 8, 2017, 7:35:49 AM8/8/17
to std-pr...@isocpp.org

> On 8 Aug 2017, at 15:42, wei zhang <lala.wi...@gmail.com> wrote:
>
> What if a lib that doesn't use directly_newed_ptr? How can I check the ptr is directly newed if I get the ptr from a lib?
>

You'll need a way to annotate pointers created by `new` anyway, whether using a new type xxx_ptr (or existing `std::unique_ptr`), introducing a new keywords `safe`, or using even C++ attribute (as compilers are free to ignore unknown attributes, using attribute here may be a bad choice.).

Actually I do not see much difference between `safe T*` and `std::unique_ptr<T>`, given your use cases. (e.g. Use case `std::shared_ptr<T>(safe T*)` is quite similar to `std::shared_ptr<T>(std::unique_ptr<T>)`).

OTOH, I'd like to suggest you to use `T*` only for non-owning pointers, and wrap all the owning pointers in some smart pointers. This way the concerns about where the pointer came from should be much less (or not at all).

> 在 2017年8月8日星期二 UTC+8上午1:53:30,Marcin Jaczewski写道:
>
>
> On Monday, August 7, 2017 at 6:37:02 AM UTC+2, wei zhang wrote:
> This actually is not a proposal, I don't even know how to implement it. But we can discuss it.
> I'm always thinking a pointer that directly created by new is different from by other meanings.
> A * ptr = new A();
> Here we can ensure that this ptr is safer than which's retrieved by following syntax,
> A* ptr = &a;
> or
> A* ptr = &(ptrB->a); which *ptrB is the structure contains A a;
> or
> A* a = &a_vector[0]; here a_vector is vector<A>
>
> The ptr directly created by new can be treated as an object's handler. And in most cases this ptr will be valid until you call delete ptr manually or by gc_count to 0 (in shared_ptr).
>
> Actually in some cases, we should only accept that type of ptr. E.g. in shared_ptr<A>( A* ptr); (this example even hope you write new A() inside the parenthesis )
>
> But the problem is how to track that information during runtime.

Note that if runtime checks for `safe` are needed, ABI incompatibilities and performance degradation are likely to be introduced.
> 1. We might use a new keyword "safe" or "unsafe" when creating that ptr (e.g. safe A * ptr = new A() ), but it requires all functions and structs use the safe syntax to accept the safe ptr even for old libs, otherwise the "safe" information will be lost after passing to the functions and structures.
> 2. We could provide safe_cast<>() to convert an unknown safe ptr to safe ptr with runtime check. So that for a ptr is safe or unsafe we need runtime support.
> 3. We could provide static_safe_cast<>() for an unknown safe ptr to a safe ptr, without runtime check.
> 4. How to treat A* ptr1 = new A() and A* ptr2 = new A[100]{} , do we treat ptr2 as safe or not?
> 5. char * bytes = new char [sizeof(A)]; safe A * ptr = new (bytes) A{} should be forbidden because replace new is unsafe, you will only get unsafe A * ptr = new(bytes) A{}. I'm wondering we should make crash directly if you do so. The only correct way is
> void * bytes = malloc(sizeof(A) ); A* ptr = new (bytes) A{}
> 6. struct A{B firstVar;}; A * ptr = new A(); B * ptr2 = reinterpret_cast<B*>(ptr); safe B* ptrB = dynamic_safe_cast<B*>(ptr2). We should get null even if ptr2 is actual B * type.
> 7. in delete ptr; C runtime should check if the ptr is of safe type A. (If with some compile flag)
>
>
> I think it will be useful especially when someone want to provide a gc manager in c++ language.
>
> Use separate type for that. Something in line of `std::shared_ptr` or `std::unique_ptr`. You can define nearly all operation needed by you on this new type.
>
>
> --
> You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
> To post to this group, send email to std-pr...@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/fa633616-ff7a-44ad-80ac-880cf1d0051c%40isocpp.org.

Nicol Bolas

unread,
Aug 8, 2017, 12:02:28 PM8/8/17
to ISO C++ Standard - Future Proposals
On Tuesday, August 8, 2017 at 3:42:36 AM UTC-4, wei zhang wrote:
What if a lib that doesn't use directly_newed_ptr?  How can I check the ptr is directly newed if I get the ptr from a lib?

If a library function returns a pointer that you have to delete, then that library's documentation will tell you. Or it will use `gsl::owner<T*>` or something similar. It's on the library to provide you the information you need to effectively use its functions.

Arthur O'Dwyer

unread,
Aug 8, 2017, 7:38:15 PM8/8/17
to ISO C++ Standard - Future Proposals
On Tuesday, August 8, 2017 at 12:42:36 AM UTC-7, wei zhang wrote:
What if a lib that doesn't use directly_newed_ptr?  How can I check the ptr is directly newed if I get the ptr from a lib?

To clarify and amplify what other people are telling you: You do not need to know whether a pointer is "directly newed". That's not a thing. What you need to know about a pointer is, "When I'm done using this pointer, should I call delete on it? or delete[]? or free()? or something else? or nothing?"  And so what you are looking for is a way to attach that "deleter" information to the pointer type, strongly and statically, and even so that it happens automatically when you finish using the pointer.

This idea "strongly and statically, and even so that it happens automatically when you finish using the pointer" is known in C++ as RAII.

The idea of using RAII on a pointer type is known in C++ as smart pointers.

C++11 introduced two smart-pointer types, either one of which can be used to solve your problem. std::unique_ptr<T, D> has a destructor that calls D(T), and std::shared_ptr<T> has a destructor that calls some type-erased function provided dynamically at constructor time.

If you have a function that returns the result of "new" (what we might call an "indirectly newed pointer" :)), you should be wrapping the pointer in unique_ptr the first chance you get. That is, instead of

    X *foo() { return new X; }

you should be using

    auto foo() { return std::unique_ptr<X>(new X); }

or, much much better,

    auto foo() { return std::make_unique<X>(); }

This solves your problem because it attaches the data about "how do I free this pointer" directly to the pointer object itself. You no longer have to track that information manually.

HTH,
Arthur

Will Zhang

unread,
Aug 10, 2017, 7:16:14 AM8/10/17
to std-pr...@isocpp.org
The problem is that it doesn't everywhere use  std::xxxx_ptr.  And I don't think for a C++ programing it should use std::xxxx_ptr everywhere.  


The philosophy is in current c/c++, a pointer is just a memory address.  Now I hope at least we are able to know if a pointer is just an address or it's an object, by c++ language itself.

Someone may ask is c++ an object oriented language?  Most of us will say yes, "but we don't know if a pointer is an object or just an address" someone will added.

Thanks
Will Zhang


Will Zhang

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Nicol Bolas

unread,
Aug 10, 2017, 10:21:49 AM8/10/17
to ISO C++ Standard - Future Proposals
On Thursday, August 10, 2017 at 7:16:14 AM UTC-4, wei zhang wrote:
The problem is that it doesn't everywhere use  std::xxxx_ptr.  And I don't think for a C++ programing it should use std::xxxx_ptr everywhere.

... why not? It solves your problem, doesn't it?

The philosophy is in current c/c++, a pointer is just a memory address.  Now I hope at least we are able to know if a pointer is just an address or it's an object, by c++ language itself.

Well, that's not gonna happen. We're not going to create yet another language-created construct like `T*` for something this trivial. Since 100% of code today uses pointers rather than this new `T~`, that means nobody's code will be in any way improved without them doing manual work.

And if they have to change from `T*` to `T~`, they could just as easily change from `T*` to `owner<T*>`.

Someone may ask is c++ an object oriented language?  Most of us will say yes, "but we don't know if a pointer is an object or just an address" someone will added.

"Most of us" will most certainly not say "yes". And quite frankly, the first bit of non-OOP most of us will think of is not the fact that a pointer doesn't have to be a valid pointer.

Thiago Macieira

unread,
Aug 10, 2017, 11:51:59 AM8/10/17
to std-pr...@isocpp.org
On quinta-feira, 10 de agosto de 2017 04:16:10 PDT Will Zhang wrote:
> The philosophy is in current c/c++, a pointer is just a memory address.
> Now I hope at least we are able to know if a pointer is just an address or
> it's an object, by c++ language itself.

Even assuming the rest of your arguments were valid, which I don't think they
are, this bit here is not what you want to know. First of all, what would a
pointer be pointing to if not to an object?

More importantly, pointing to a sub-object of a larger object is still
pointing to an object. But that isn't compatible with everything else you
said.

No, I agree with Arthur: you don't want to know what the pointer points to.
You want to know what to do with the pointer once you no longer need it.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

Reply all
Reply to author
Forward
0 new messages