JAL said:
No... but smart pointers replace the try catch also
My point is that the C# using keyword works for trivial cases when you
locally allocate and object and delete it right away. But C# using
doesn't work when the object has a longer life span, but still requires
automatic destruction. How do you store a list of resources in a
container/collection with deterministic cleanup?
All you're showing is that
C++ auto_ptr<T> t(new T)
is the same as
C# using(T t = new T)
That I agree with. But the real differences begin to show up when I can
do in C++ vector<shared_ptr<T> >. In C# I don't think there's a solution
to it. I actually tried to put objects into a List<T> using C# 2.0, and
it didn't automatically call Dispose on T. So List<T>:
ispose (if it
has such a thing at all) doesn't call Dispose for the contained objects.
I think it would be nice if .NET collections had a Dispose method, which
would call Dispose for its members. But even that wouldn't solve a lot
of other problems that reference counted shared_ptr does. What if a
single resource has 2 object copies, both handling the same resource,
and the actual resource should only be disposed when the last object
copy goes out of existence?
As Carl said, pure managed memory reclamation is not the same thing as
resource reclamation. In C# you don't worry about releasing allocated
managed memory, but you still have the burden of reclaiming resouces,
and the language doesn't provide a very good support for that. The using
keyword only solves that for trivial cases, when the object is create
and delete in the *same scope*, which can't always be ensured. In
complex applications resources are stored in containers, in other
objects, and they're destructed in a very complex way.
One more advantage of the boost implementation is weak_ptr. It clearly
separates ownership semantics (shared_ptr) from reference semantics
(weak_ptr). Using weak_ptr you can be sure that you don't leave trash
objects behind accidentally. It automatically makes sure that when the
last shared_ptr goes out of existence, all weak_ptr's that refer to the
object get NULLed out automatically. I challenge you to implement this
in C#, without manually having to call Dispose. I believe it's doable in
C++/CLI, even if we don't initially have such a solution yet.
I'd like to note that even in C++/CLI the standard .NET containers
suffer from deterministric destruction problems:
using namespace System::Collections::Generic;
ref class Guarded
{
public:
~Guarded() { Console::WriteLine(L"~Guarded"); }
};
int main(array<System::String ^> ^args)
{
List<Guarded^> items;
items.Add(gcnew Guarded);
return 0;
}
Although "items" uses stack semantics, when it goes out of scope it
doesn't Dispose its members. And trying to do
List<Guarded> items
doesn't work, because List<T> is a generic, not a template. I'm not sure
if the upcoming STL.NET will solve this. It's very concerning when I
program in .NET, even in C++/CLI. I simply can't use the .NET containers
to store objects that wrap unmanaged types, because the Dispose pattern
is broken. I think it's just a matter of time before really good C++/CLI
container implementations come out, where we'll be able to write
vector<shared_ptr<ManagedClass> >
Not having the proper tools for this problem, I feel like I live in
danger, just like C programmers do (whether they admit it or not). Or
even more so, because C programmers are not used to exceptions, but .NET
programmers must think of exception safety. Every system that provides
exceptions but no exception safety is a disaster waiting to happen.
Tom