Date: Mon, 25 Aug 2025 10:46:38 +0200
> On Aug 25, 2025, at 9:40 AM, organicoman <organicoman_at_[hidden]> wrote:
>
> There is no delete inside the code, so as an implemeter I will express it by taking the pointer by copy not by reference....it's an indication to the caller that the code doesn't contain any 'delete' expression.
I thought you wanted to detect if there is an accidental delete inside the code. For this to work reliably you need to always take a T*& and never a T*.
> In one of your previous reply, you mentioned that if the pointer is reassigned without using it, the compiler can optimize it out and dangle the references.
> So I started investigating. And I found that even for optimization level 0, the reference to pointer will collapse to the pointer itself.
> The compiler is smart enough to tell that there is no usage of the address of the pointer, but only of its value, so it collapse all reference to the pointer itself.
> So no performance drop, no double indirection and no extra pointer management.
(Sorry, I screwed up commenting on the previous response.)
I’m not sure what exactly you have experimented with. What you are saying is true for the local scope, but most certainly not for calling non-inlined functions (which would be the case for library calls). It would break the C++ type system if this were true. You need to just write a function that takes a T*& and compile it standalone. It will show a double indirection for the function parameter.
> Also I found the answer to your observation, so by the time the pointer is reassigned, all its previous references already ended their lifetime. So no dangling reference.
> One case which was difficult to reason about is threading(async ref),
Since you now brought up threads: you need to mention them in the proposal. A valid answer is that there are no protections for threads (I don’t think delete currently has any similar protections). Your proposal could still be useful because I suspect that most code where your proposal would be relevant isn’t thread-related.
> because I don't have a delete operator that behaves as my proposal.
In your case this is not really a good excuse. Sometimes there is the suggestion to “implement it in clang” which is really hard if you don’t have a clue at all. However, in your case you can implement a my_delete(void*&) function and use it everywhere where a delete is currently used. This would give you some experience how useful the feature actually is. It wouldn’t have the same syntax you want, but it would work in the same way.
>
> As for the cost of the proposal:
>
> Given
>
> void Foo(T* p)
> {
> // delete is somewhere here and not necessarily on p
> }
>
> When changed to
>
> void Foo(T* &p)
> {
> }
>
> 1- as a caller of 'Foo' i will expect a delete inside the code
> 2- as a caller of 'Foo' i can inspect the side effects on my pointer i passed, or simply do nothing since I'm protected by delete assigning nullptr.
> 3- as an implemeter of 'Foo' I'm conveying the idea that there is a delete inside, even if it is not on the pointer argument itself.
> 4- as an implemeter of 'Foo' if I promise to the caller that I will not own the pointer, yet, the caller finds it nullptr, then please report that bug.
> 5- as a implemeter of 'Foo', if by any means I change the value of the pointer, yet I don't delete it, then I will get the bug explode at my face before it reaches my clients.
I initially read this wrong. However, you are saying that 3. if there is any delete inside the function all pointer arguments need to be references to pointers. Otherwise they should be plain pointers. This would mean in reality that when I am doing maintenance on a function and add a delete I have to remember to check the function arguments? Have you heard of semantic versioning? Only break the ABI if the major version of your library changes.
The only viable way is to /always/ take pointers by reference. This also helps which teachability (teachability should also be addressed in any proposal).
>
> Consider this expl:
>
> SomeType* find(T* &p, size_t len, Pred pre)
> {
> SomeType* pt = new SomeType;
> size_t idx = 0;
> While (index<len && !Pred(*p++)) ++idx;
> if(idx != len) return pt;
> else
> {
> delete p; // mistake pt not p
> return pt;
> }
> }
>
> This code will explode in my face before even I ship it to my clients, since p doesn't point to anything allocated before.
>
> All in all, you need to add one character (&) to any function that has a 'delete' expression inside, update its signature in the header files and upload it to the clients.
> Now how to change delete implementation without breaking ABI, that's out of my expertise, but I feel it is doable.
You are wrong about that. It is not only not possible, but it would go against the C++ core principle of strong type checking for function calls.
>
> I hope that i cleared some of the confusion around the proposal, if not then, I will try to write a document as per your request (but I'm a bit lazy :b )
>
> There is no delete inside the code, so as an implemeter I will express it by taking the pointer by copy not by reference....it's an indication to the caller that the code doesn't contain any 'delete' expression.
I thought you wanted to detect if there is an accidental delete inside the code. For this to work reliably you need to always take a T*& and never a T*.
> In one of your previous reply, you mentioned that if the pointer is reassigned without using it, the compiler can optimize it out and dangle the references.
> So I started investigating. And I found that even for optimization level 0, the reference to pointer will collapse to the pointer itself.
> The compiler is smart enough to tell that there is no usage of the address of the pointer, but only of its value, so it collapse all reference to the pointer itself.
> So no performance drop, no double indirection and no extra pointer management.
(Sorry, I screwed up commenting on the previous response.)
I’m not sure what exactly you have experimented with. What you are saying is true for the local scope, but most certainly not for calling non-inlined functions (which would be the case for library calls). It would break the C++ type system if this were true. You need to just write a function that takes a T*& and compile it standalone. It will show a double indirection for the function parameter.
> Also I found the answer to your observation, so by the time the pointer is reassigned, all its previous references already ended their lifetime. So no dangling reference.
> One case which was difficult to reason about is threading(async ref),
Since you now brought up threads: you need to mention them in the proposal. A valid answer is that there are no protections for threads (I don’t think delete currently has any similar protections). Your proposal could still be useful because I suspect that most code where your proposal would be relevant isn’t thread-related.
> because I don't have a delete operator that behaves as my proposal.
In your case this is not really a good excuse. Sometimes there is the suggestion to “implement it in clang” which is really hard if you don’t have a clue at all. However, in your case you can implement a my_delete(void*&) function and use it everywhere where a delete is currently used. This would give you some experience how useful the feature actually is. It wouldn’t have the same syntax you want, but it would work in the same way.
>
> As for the cost of the proposal:
>
> Given
>
> void Foo(T* p)
> {
> // delete is somewhere here and not necessarily on p
> }
>
> When changed to
>
> void Foo(T* &p)
> {
> }
>
> 1- as a caller of 'Foo' i will expect a delete inside the code
> 2- as a caller of 'Foo' i can inspect the side effects on my pointer i passed, or simply do nothing since I'm protected by delete assigning nullptr.
> 3- as an implemeter of 'Foo' I'm conveying the idea that there is a delete inside, even if it is not on the pointer argument itself.
> 4- as an implemeter of 'Foo' if I promise to the caller that I will not own the pointer, yet, the caller finds it nullptr, then please report that bug.
> 5- as a implemeter of 'Foo', if by any means I change the value of the pointer, yet I don't delete it, then I will get the bug explode at my face before it reaches my clients.
I initially read this wrong. However, you are saying that 3. if there is any delete inside the function all pointer arguments need to be references to pointers. Otherwise they should be plain pointers. This would mean in reality that when I am doing maintenance on a function and add a delete I have to remember to check the function arguments? Have you heard of semantic versioning? Only break the ABI if the major version of your library changes.
The only viable way is to /always/ take pointers by reference. This also helps which teachability (teachability should also be addressed in any proposal).
>
> Consider this expl:
>
> SomeType* find(T* &p, size_t len, Pred pre)
> {
> SomeType* pt = new SomeType;
> size_t idx = 0;
> While (index<len && !Pred(*p++)) ++idx;
> if(idx != len) return pt;
> else
> {
> delete p; // mistake pt not p
> return pt;
> }
> }
>
> This code will explode in my face before even I ship it to my clients, since p doesn't point to anything allocated before.
>
> All in all, you need to add one character (&) to any function that has a 'delete' expression inside, update its signature in the header files and upload it to the clients.
> Now how to change delete implementation without breaking ABI, that's out of my expertise, but I feel it is doable.
You are wrong about that. It is not only not possible, but it would go against the C++ core principle of strong type checking for function calls.
>
> I hope that i cleared some of the confusion around the proposal, if not then, I will try to write a document as per your request (but I'm a bit lazy :b )
Received on 2025-08-25 08:46:51