After trying out the Movable<TResource> type from Move Semantics for IDisposable
I discovered a fatal flaw in its implementation: it is incompatible with struct
memberwise copy semantics.
Recall that Movable<TResource> was defined as follows:
With this code, if wrapWithDecorator is false, both s1 and s2
have non-null references to stream. At the end of the CreateStream()
function, s1 will call stream.Dispose(), and thus the function ends
up returning a disposed stream, which is invalid.
One way to fix this is to never copy Movables and write code like this:
However, this is extremely error-prone. I initially looked for ways
to define a non-copyable struct, but I was reminded of
Eric Lippert’s words:
The relevant feature of value types is that they have the semantics of
being copied by value, not that sometimes their deallocation can be
optimized by the runtime.
Therefore, I changed Movable<TResource> to use reference copy semantics
by changing it to a class:
1
2
3
4
classMovable<TResource> : IDisposable where TResource : class, IDisposable
{
// everything else as before}