Alexei said:
Now, does it matter if the object is created with gcnew or by calling a
function? No, IMO. The same code I can rewrite with using
fi.OpenRead():
{
FileStream ^ fs = fi.OpenRead();
try {
} finally {
delete fs;
}
}
Something like this would be nice, but it can't be done the way you're
trying to do it.
What leads me to simply:
FileStream fs(fi.OpenRead());
I think the code above would expand to
FileStream^ fs = gcnew FileStream(fi.OpenRead());
[...]
and there is no such copy constructor in FileStream (and even if there was
one, you wouldn't want to make a copy in this case).
I can't understand the point of having copy-constructors for ref classes.
There is such a thing as copy c'tor and assignment operator in C++/CLI.
Because what if you want to make a copy? You could always define a static
member (class method) name CopyMe, but C++/CLI was designed to be as
conforming with C++ as possible. The stack syntax with ref classes has to
work like stack objects in native C++, otherwise you're inventing a new
language that has nothing to do with C++. Exactly that happened with the
old MC++, where the destructor syntax was used for the finalizer. Such a
radical change has disadvantages, because C++ programmers have certain
expectations about the language, such as the copy c'tor syntax, even if
it's implemented in the underlying .NET layer differently.
What you're asking for is
cli::auto_ptr<FileStream> fs(fi.OpenRead());
which may or may not exist. If it doesn't, you can try to write your own.
It would have a little bit of an overhead, but only a couple of extra CLI
instructions.
Here's an auto pointer template that I wrote, although it has a completely
different purpose (to store unmanaged objects inside a managed wrapper):
#pragma once
template <class T>
public ref class CliScopedPtr
{
typedef CliScopedPtr<T> this_type;
public:
CliScopedPtr()
: ptr(nullptr)
{
}
explicit CliScopedPtr(T* p)
: ptr(p)
{
}
~CliScopedPtr()
{
delete ptr;
}
T* get()
{
return ptr;
}
T& operator*()
{
return *ptr;
}
T* operator->()
{
return ptr;
}
bool assigned()
{
return ptr != nullptr;
}
void swap(CliScopedPtr% other)
{
T* tmp = other.ptr;
other.ptr = ptr;
ptr = tmp;
}
void swap(CliScopedPtr^ other)
{
T* tmp = other->ptr;
other->ptr = ptr;
ptr = tmp;
}
void reset()
{
this_type().swap(this);
}
void reset(T* p)
{
this_type(p).swap(this);
}
private:
T* ptr;
CliScopedPtr(CliScopedPtr%); // disabled
CliScopedPtr% operator=(CliScopedPtr%); // disabled
};
Credit goes to boost::scoped_ptr for the idea.
Example:
class Unmanaged { };
CliScopedPtr<Unmanaged> ptr(new Unmanaged);
Tom