Talk:C++/CLI
Problematic sentence
The article has a sentence that reads as follows: "The importance of this change becomes crucial when managed and unmanaged code is mixed: where you previously saw a sea of pointers, you can now tell which objects are under garbage collection and which must be destroyed."
How is this possible? Regular C++ allows memory to be garbage-collected. Additionally, regular C++ supports smart pointers which are not manually destroyed. Given, then, that regular pointers may be garbage collected and may not need to be destroyed, I do not believe the sentence accurately describes the usefulness of handles compared to pointers. --Yamla 03:51, 16 January 2006 (UTC)
- "Smart pointers" in regular C++? I think you're talking about references, which are nothing but a somewhat type-safe and cut down version of pointers. If such pointers exist and are really a feature of regular (standard) C++, not just a vendor extension, please enlighten me: I would surely use them!
- Smart pointers are now part of TR1. TR1 is standard C++. They are also easy to add to C++ even if your compiler is behind the times. --Yamla 16:53, 16 January 2006 (UTC)
- I don't know to which point is that TR1 incorporated into the C++ standards _and_ current C++ compilers. Do you mean that the only library I actually need to use is the standard C++ library (the one with vector<T>, cout, etc.)? Habbit 19:00, 16 January 2006 (UTC)
- Assuming what I currently know (no such smart pointers) as true, "regular" C++ indeed allows memory to be garbage-collected (through new and delete). And so does C (through malloc and free). However, the new part in C++/CLI is automatic garbage collection: you just create the object with gcnew. When it goes out of scope (when all handles to it are no longer accesible), that object is elegible for automatic destruction that will be performed when memory is needed or System::GC::Collect() is called.
- Oh, and, of course, you can do similar things with your own GC system, such as Boehm, but here you don't even have to worry about calling a modified version of new. If you try to create a managed object with new instead of gcnew, you'll receive an error.
- Well, you do need gcnew instead of regular new. So wouldn't that be a modified version of new? Obviously, this depends on your point of view. --Yamla 16:53, 16 January 2006 (UTC)
- By "modified version of operator new" i meant an overriden version of global operator new _or_ something that passes through one of the GC classes. If you use your own GC system, you can still create potential memory leaks by using the old (regular) version of operator new, which is impossible in C++/CLI because, as I said above, trying to create a managed object with operator new instead of operator gcnew or vice versa will throw a compile error. I don't know, however, what do keywords like int map to: the system-dependant length C++ int primitive or the 32-bit CLR System::Int32?. Habbit 19:00, 16 January 2006 (UTC)
- Last but not least, that sentence is just comparing C++/CLI with its predecessor, Managed Extensions for C++, where both managed and unmanaged objects used the pointer (*) syntax and were created with operator new (String* a = new String()). In this new version, managed objects use the handle (^) syntax and are created with operator gcnew (String^ a = gcnew String()), while unmanaged objects keep their pointer syntax (CMyUnmanagedClass* a = new CMyUnmanagedClass()), thus making the distinction clearer: you don't have to worry about destroying objects with the handle syntax.
- Habbit 16:49, 16 January 2006 (UTC)
- I thought Managed Extensions for C++ also supported regular C++, in which case the sentence is worded somewhat difficultly. Anyway, please give me feedback on what I've written above and then perhaps I'll try suggesting an alternate wording here. --Yamla 16:53, 16 January 2006 (UTC)
- You are partially right: Managed Extensions for C++ (MEC++) were conceived, as the name suggets, as a superset to standard C++ to support CLR. However, C++/CLI can be thought of as a different language whose syntax "happens" to be compatible with that of C++ for unmanaged code, and which output can either target a given machine (unmanaged code) or the .NET VM (managed code). That is, at least, my view... What do you think? Habbit 19:00, 16 January 2006 (UTC)
Using block
To Habbit: Examples in C# and C++/CLI are not equivalent. Reason: MyClass auto in C++ example "lives" to the end of function. If you want same behaviour in C# example, you should use using block over the entire function. That is the reason I modified using block in past. I found nothing strange about that modification. Can you explain to me what is so strange about that? Jakiša Tomić 19:33, 5 April 2006 (UTC)
From that point of view, nothing, I just found strange that you made the using block encompass the other try/finally block. Besides, I added the comments to clarify the scope of the variables: I think the using block is clearer if it does not get mixed with the "user equivalent code" Habbit 23:22, 5 April 2006 (UTC)
By the way, the whole-method-spanning using block is clumsier, the point of the example was to show _roughly_ equivalent code about deterministic destruction, so I hope the comments clarify what I considered was clear X_X Habbit 00:18, 6 April 2006 (UTC)
Ok, comments clarify all. Cheers! Jakiša Tomić 10:41, 6 April 2006 (UTC)
you do know that this does not even scratch the surface....
As above, how about the introduction to generics, type safty, and a bunch more? I will be glad to put this up, just I don't have the time right now. Maybe next week.Eagle talk 06:24, 7 May 2006 (UTC) they are part of .Net 2.0 and available to all .net languages, aren't they? --Skyfiler 18:26, 7 May 2006 (UTC)
- Yes, though some of it is C++/CLI specific.Eagle talk 02:49, 7 June 2006 (UTC)
dispose and finalize together
How could I know, as stated in the article, whether the (deterministic) destructor has already been called? --euyyn 02:30, 29 June 2006 (UTC)
- Simple: as the deterministic destructor (~ClassName, or IDisposable::Dispose implementation) does not truly destroy the object, you can create a private bool disposed which is set to true in the ~ClassName and then check for this->disposed in both destructors: thus you secure the invocation of Dispose while at the same time avoiding its double invocation. Also, you can use GC::SupressFinalize to get rid of the small performance penalty of calling an unneeded finalizer. A naïf example with a lot of redundancy:
class DestructorTest { public: DestructorTest() { this->disposed = false; } ~DestructorTest() // As ~CN is really IDisposable::Dispose, is it forced to be public? I dunno { if (!this->disposed) // Dispose this->disposed = true; System::GC::SupressFinalize(this); // Avoid !CN getting called (but it wouldn't matter, see below) } protected: !DestructorTest() { if (!this->disposed) this->~DestructorTest(); // Is this the right way of invoking ~CN? Sorry, I'm mostly a C# guy } private: bool disposed; };