Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / Managed C++ / June 2005

Tip: Looking for answers? Try searching our database.

Beta 2: Automatic Dispose inaction?

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Alexei - 19 Jun 2005 21:27 GMT
Hello,

The following doesn't compile due to absence of the copy constructor in class FileStream:

FileInfo ^ fi = ...;
FileStream fs = fi->OpenRead();

The compiler is Beta 2.  Is this supported?  Planned to be supported?
Carl Daniel [VC++ MVP] - 20 Jun 2005 00:54 GMT
> Hello,
>
[quoted text clipped - 3 lines]
> FileInfo ^ fi = ...;
> FileStream fs = fi->OpenRead();

FileStream^ fs = fi->OpenRead();

-cd
Alexei Zakharov - 20 Jun 2005 01:04 GMT
>> Hello,
>>
[quoted text clipped - 5 lines]
>
> FileStream^ fs = fi->OpenRead();

Don't answer just to answer.  Look here: http://blogs.msdn.com/arich/ (DF
pattern).
Willy Denoyette [MVP] - 20 Jun 2005 07:51 GMT
>>> Hello,
>>>
[quoted text clipped - 8 lines]
> Don't answer just to answer.  Look here: http://blogs.msdn.com/arich/ (DF
> pattern).

This pattern is for C++/CLI implemented classes only, the FCL are written in
C# and their classes can't be "stack allocated". So, what you should do is,
allocate the object on the heap and manually dispose.

Willy.
Alexei - 20 Jun 2005 09:45 GMT
> This pattern is for C++/CLI implemented classes only, the FCL are
> written in C# and their classes can't be "stack allocated". So, what
> you should do is, allocate the object on the heap and manually
> dispose.

It doesn't seem plausible since I can write:
   FileStream fs("myfile", FileMode::Create);
And it will work.
Willy Denoyette [MVP] - 20 Jun 2005 11:36 GMT
>> This pattern is for C++/CLI implemented classes only, the FCL are
>> written in C# and their classes can't be "stack allocated". So, what
[quoted text clipped - 4 lines]
>    FileStream fs("myfile", FileMode::Create);
> And it will work.

Sorry for not being more explicit. The FileInfo->OpenRead returns a
FileStream object reference (heap allocated), you can't assign it to a stack
allocated variable.
So what you could do is...

FileInfo fi(".....");
FileStream ^fs = fi.OpenRead();

Willy.
Alexei - 21 Jun 2005 05:21 GMT
>>> This pattern is for C++/CLI implemented classes only, the FCL are
>>> written in C# and their classes can't be "stack allocated". So, what
[quoted text clipped - 8 lines]
> FileStream object reference (heap allocated), you can't assign it to
> a stack allocated variable.

There is no such thing as stack allocation for ref classes.  So the whole
your argument is moot.

{
   FileStream fs(...);
}

is equivalent to:

{
   FileStream ^ fs = gcnew FileStream(...);
   try {
   } finally {
       delete fs;
   }
}

See, the object is still on GC heap.  You can't place it on stack.  What you
have is just a language construct that sort of looks like a stack-based
placement.

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;
   }
}

What leads me to simply:

FileStream fs(fi.OpenRead());

I can't understand the point of having copy-constructors for ref classes.
.NET object model is fundamentally different from C++ object model.  There
is no copy-construction per se in .NET (besides trivial bitwise copy for
value classes).  Objects are passed around by reference not by value as in
C++, so copying is not needed.  I don't see the reason for C++/CLI to
introduce an idiom that can't have any relevence for .NET programming.

> So what you could do is...
>
> FileInfo fi(".....");
> FileStream ^fs = fi.OpenRead();
Nemanja Trifunovic - 21 Jun 2005 16:38 GMT
> There is no such thing as stack allocation for ref classes.

The point is "stack semantics", not "stack allocation". The memory for
the object is indeed allocated from GC heap, but it is (mostly)
irrelevant here.
Willy Denoyette [MVP] - 21 Jun 2005 17:22 GMT
Who's talking about stack allocated reference classes,  I said "assign it to
a stack allocated variable" right?
I know ref. classes aren't stack allocated, they have stack semantics.

For the compiler there's a difference between:
FileStream fs = fi->OpenRead();
and
FileStream fs(...);
The first is an assignment of a "stack allocated variable", with stack
semantics, to a value with "reference" semantics (of type FileStream),
returned by a (C#) function call. This is something that the current C++
compiler can't handled, why he's insisting on a copy constructor is beyond
me, ref class can't have copy constructors.
The latter is a constructor call, that upon return (note: nothing is
returned from the constructor!!!), initializes a stack allocated variable
with stack semantics. This initialization is completely handled by the C++
compiler.

Herewith a simple sample that illustrates the issue:

// C#
 public class Tester
{
   public Test GetTest()
   {
     Test t = new Test();
     return t;
   }
}

 public class Test
 {...
 }
}

// C++
Tester t;
Test tt = t.GetTest();

Willy.

>>>> This pattern is for C++/CLI implemented classes only, the FCL are
>>>> written in C# and their classes can't be "stack allocated". So, what
[quoted text clipped - 56 lines]
>> FileInfo fi(".....");
>> FileStream ^fs = fi.OpenRead();
Tamas Demjen - 21 Jun 2005 17:40 GMT
> 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():
[quoted text clipped - 6 lines]
>     }
> }

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
Willy Denoyette [MVP] - 21 Jun 2005 19:22 GMT
>> 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
[quoted text clipped - 129 lines]
>
> Tom

Guess what, just installed the June CTP of VS2005, and they included exactly
this through the auto_handle template in the msclr namespace.

#include <msclr\auto_handle.h>
...
FileInfo fi("......");
msclr::auto_handle<FileStream> fs(fi.OpenRead());
..

Willy.
Tamas Demjen - 21 Jun 2005 19:55 GMT
> Guess what, just installed the June CTP of VS2005, and they included exactly
> this through the auto_handle template in the msclr namespace.
[quoted text clipped - 6 lines]
>
> Willy.

Thank you for the information, it's very good to know. It will solve the
original poster's problem.

My CliSmartPtr, however, is slightly different. auto_handle<T> is a
managed smart pointer around T^. CliSmartPtr<T> is a managed smart
pointer around T*. I intended to use it in situations like

ref class C
{
private:
   CliSmartPtr<Unmanaged> unmanaged;
[...]
};

It yet has to be tested with a real-world project. :-)

Tom

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.