Replies: 6 comments 7 replies
-
See also (in no particular order): |
Beta Was this translation helpful? Give feedback.
-
Perhaps an optimised reflection based extension method would be able to deal with this. It could act like a normal struct copy but call the appropriate method on any member which is a smart pointer. This would need to be a deep clone to catch deep smart pointers. As whether or not a particular struct contains a smart pointer could be considered an implementation detail, it may have to become standard to use this extension method for practically all struct copies. This is getting quite unwieldy and I have concerns over whether it could be anywhere near as fast as it would need to be. I don't think that this is on track to be a "good" implementation by any reasonable definition. |
Beta Was this translation helpful? Give feedback.
-
I think a good definition for a "good enough" implementation may be that it is not completely safe, but has a deep and wide pit of success. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
The closest we can get today is If C# had non-defaultable value types and a way to enforce non-copyable value types, the overhead would be substantially reduced as shown in dotnet/roslyn#42710. This just leaves the overhead of the |
Beta Was this translation helpful? Give feedback.
-
@SamPruden This is only peripherally connected with your issue, but I've tried to build something that does some low level operations with pointers before and got to a stage where my work was halted because of this problem which has still not been fixed. The type The actual issue now is here. The use case here was the desire to manage large areas of process address space that sits outside of the CLR. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Context
The Unity game engine's recent move towards its Burst compiler has created a number of scenarios where C++ style features may be useful in C#.
For those that don't know, Unity now includes the Burst compiler, which allows specific sections of C# code to be run through LLVM and be heavily optimised. This is a big part of their push towards the DOTS (Data Oriented Technology Stack) which is a major overhaul of how the engine works and brings in major performance improvements. Burst compiled code has some significant restrictions, one of which is that it can't touch managed types.
This means that memory is all managed through custom struct container types which don't work with garbage collection. The
IDisposable
pattern is used to deallocate them. This makes ownership management quite tricky because we're back to the early C++ days of manually keeping track of making sure each allocated chunk of memory is deallocated exactly once.Question
C++'s solution to this is smart pointers. I'm wondering how close we can get to a good smart pointer implementation in C#, and what feasible changes to the language may get us closer if necessary.
The problem of managing ownership of
IDisposable
types isn't new, but doing so without using classes and where performance is of paramount importance is unusual.I don't have extensive C++ experience, so my intuition for the subtle requirements here isn't good. My understanding of smart pointers is that they rely heavily on being able to override the copy behaviour of structs.
unique_ptr
simply prevents implicit copying and only allows explicit APIs to copy and transfer ownership in a controlled way.shared_ptr
overrides copying to implicitly increment a reference counter. In both cases, a destructor is implicitly called when the smart pointer goes out of scope. Forunique_ptr
this deallocates the memory, and forshared_ptr
this decrements the reference counter and deallocates if zero.There are two major blockers to doing this in C#: We cannot modify copy behaviour, and we cannot implement finalizers for structs.
We could attempt to approximate this with some form of
struct CountedReference<T>
type which providesClone
andDispose
methods to explicitly fulfil the roles of copying and destructing respectively. This would be a bit clumsy to use, but fairly safe if it weren't for the fact that it would still be easy to accidentally make implicit copies of this type without callingClone
. That vulnerability means that we would only ever have a (dangerous) pretence of safety and I predict that bugs arising from accidentally copying a counted reference without usingClone
would be common.There may be some trick using the
ref
like behaviours recently added to C#, but I'm not aware of what it would be.My prediction is that the best that we can do today is some version of the above mentioned
CountedReference<T>
combined with an analyser that attempts to catch all implicit copies. The basic cases for that analyser are easy, but I'm not sure how feasible it is to definitely catch every copy. Even if this is possible, we would still have an ugly scenario when we want to implicitly copy a struct that contains one of these smart pointer types. We may find that many of our structs suddenly requireClone
methods to handle this. I predict that that would lead to people lazily avoiding using the smart pointer, which isn't exactly a pit of success.What is the best way to achieve smart pointer like behaviour in C#, whilst being as fast as possible and without touching managed types, and whilst being robust to mistakes by developers who only have experience in managed / GCed environments like C#? Are there any feasible language feature additions which may help here? Copy overloading would be great, but it probably isn't feasible.
Other techniques for safely handling ownership (single and multiple) of
IDisposable
types are also of interest! They must be very fast, and they must not touch managed types. I'm interested in this academically and for the sake of experimentally implementing a solution for my own Unity project, but if a good design can be found then I'd also like to propose that Unity adopts it into their framework.Beta Was this translation helpful? Give feedback.
All reactions