www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Understanding RefCounted

reply JG <someone somewhere.com> writes:
Reading the documentation on RefCounted I get the impression that 
the following can lead to memory errors. Could someone explain 
exactly how that could happen? I suppose that problem would be 
the call something to do with front?


```
private struct RefCountedRangeReturnType(R)
{
     import std.typecons : RefCounted;
     private RefCounted!R r;
     auto empty() { return r.refCountedPayload.empty; }
     auto front() { return r.refCountedPayload.front; }
     void popFront() { r.refCountedPayload.popFront; }
     auto save() { return 
typeof(this)(RefCounted!R(r.refCountedPayload.save)); }
}

auto refCountedRange(R)(R r)
{
     import std.typecons : RefCounted;
     return  RefCountedRangeReturnType!R(RefCounted!R(r));
}
```
May 12 2021
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/12/21 3:28 AM, JG wrote:
 Reading the documentation on RefCounted I get the impression that the 
 following can lead to memory errors. Could someone explain exactly how 
 that could happen? I suppose that problem would be the call something to 
 do with front?
 
 
 ```
 private struct RefCountedRangeReturnType(R)
 {
      import std.typecons : RefCounted;
      private RefCounted!R r;
      auto empty() { return r.refCountedPayload.empty; }
      auto front() { return r.refCountedPayload.front; }
      void popFront() { r.refCountedPayload.popFront; }
      auto save() { return 
 typeof(this)(RefCounted!R(r.refCountedPayload.save)); }
 }
 
 auto refCountedRange(R)(R r)
 {
      import std.typecons : RefCounted;
      return  RefCountedRangeReturnType!R(RefCounted!R(r));
 }
 ```
You don't need to access refCountedPayload. RefCounted is supposed to be like a transparent reference type, and should forward all calls to the referenced item. I don't see how you will get memory errors from your code. Maybe you can elaborate why you think that is? -Steve
May 12 2021
parent reply JG <someone somewhere.com> writes:
On Wednesday, 12 May 2021 at 13:38:10 UTC, Steven Schveighoffer 
wrote:
 On 5/12/21 3:28 AM, JG wrote:
 Reading the documentation on RefCounted I get the impression 
 that the following can lead to memory errors. Could someone 
 explain exactly how that could happen? I suppose that problem 
 would be the call something to do with front?
 
 
 ```
 private struct RefCountedRangeReturnType(R)
 {
      import std.typecons : RefCounted;
      private RefCounted!R r;
      auto empty() { return r.refCountedPayload.empty; }
      auto front() { return r.refCountedPayload.front; }
      void popFront() { r.refCountedPayload.popFront; }
      auto save() { return 
 typeof(this)(RefCounted!R(r.refCountedPayload.save)); }
 }
 
 auto refCountedRange(R)(R r)
 {
      import std.typecons : RefCounted;
      return  RefCountedRangeReturnType!R(RefCounted!R(r));
 }
 ```
You don't need to access refCountedPayload. RefCounted is supposed to be like a transparent reference type, and should forward all calls to the referenced item. I don't see how you will get memory errors from your code. Maybe you can elaborate why you think that is? -Steve
To be honest I can't see the problem. But the following from the documentation made me wonder if I was doing something that could lead to memory problems: "RefCounted is unsafe and should be used with care. No references to the payload should be escaped outside the RefCounted object." In particular I wondered if in some special case holding a reference to front might cause a problem, but perhaps that is incorrect.
May 12 2021
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/12/21 1:16 PM, JG wrote:
 On Wednesday, 12 May 2021 at 13:38:10 UTC, Steven Schveighoffer wrote:
 On 5/12/21 3:28 AM, JG wrote:
 Reading the documentation on RefCounted I get the impression that the 
 following can lead to memory errors. Could someone explain exactly 
 how that could happen? I suppose that problem would be the call 
 something to do with front?


 ```
 private struct RefCountedRangeReturnType(R)
 {
      import std.typecons : RefCounted;
      private RefCounted!R r;
      auto empty() { return r.refCountedPayload.empty; }
      auto front() { return r.refCountedPayload.front; }
      void popFront() { r.refCountedPayload.popFront; }
      auto save() { return 
 typeof(this)(RefCounted!R(r.refCountedPayload.save)); }
 }

 auto refCountedRange(R)(R r)
 {
      import std.typecons : RefCounted;
      return  RefCountedRangeReturnType!R(RefCounted!R(r));
 }
 ```
You don't need to access refCountedPayload. RefCounted is supposed to be like a transparent reference type, and should forward all calls to the referenced item. I don't see how you will get memory errors from your code. Maybe you can elaborate why you think that is?
To be honest I can't see the problem. But the following from the documentation made me wonder if I was doing something that could lead to memory problems: "RefCounted is unsafe and should be used with care. No references to the payload should be escaped outside the RefCounted object." In particular I wondered if in some special case holding a reference to front might cause a problem, but perhaps that is incorrect.
Ah, ok. So reference counting provides a single thing you can point at and pass around without worrying about memory cleanup. But only as long as you refer to it strictly through a RefCounted struct. If you keep a pointer to something in the payload that isn't wrapped in a RefCounted struct (and specifically the original RefCounted struct), then it's possible the RefCounted struct will free the memory while you still hold a reference. You are returning from front by value, so there shouldn't be a problem with lifetime issues. However, there are possible exceptions, but they would be really rare. As an example of something that would be a bad idea: ```d struct S { int x; } int *bad; { auto rc = S(1).refCounted; bad = &rc.x; // escape a reference to the payload } // here, the scope closes and rc is freed *bad = 5; // leaving a dangling pointer that can be used ``` -Steve
May 12 2021
parent JG <someone somewhere.com> writes:
On Thursday, 13 May 2021 at 00:53:50 UTC, Steven Schveighoffer 
wrote:
 On 5/12/21 1:16 PM, JG wrote:
 [...]
Ah, ok. So reference counting provides a single thing you can point at and pass around without worrying about memory cleanup. But only as long as you refer to it strictly through a RefCounted struct. If you keep a pointer to something in the payload that isn't wrapped in a RefCounted struct (and specifically the original RefCounted struct), then it's possible the RefCounted struct will free the memory while you still hold a reference. [...]
Thank you. I was just wondering if something like what you wrote could be achieved using the range above accidentally.
May 12 2021