Talk:C++/CLI
This article is rated Start-class on Wikipedia's content assessment scale. It is of interest to the following WikiProjects: | |||||||||||||||||||||
|
Problematic sentence
[edit]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)
- Check out std::auto for a simple smart pointer implementation inside the standard template library. Traenkle (talk) 04:31, 28 November 2007 (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
[edit]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)
I changed 'auto' to 'automatic'. The choice for 'auto' is pretty inconvenient as it is a C++ keyword. .oisyn 10:40, 24 September 2007 (UTC)
you do know that this does not even scratch the surface....
[edit]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
[edit]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; };
- So... what the heck does it do, then, if it doesn't destroy the object?? What's it intended for? That should be said in the article, as it's not how "normal" destructors behave. --euyyn 08:34, 17 July 2006 (UTC)
- XD It may sound disturbing for C++ developers, but the C++/CLI destructor (deterministic, ~C syntax) does not really "destroy" the object, if by destroying it you mean to free all its memory. A .NET IDisposable::Dispose method (which is the ~C syntax becomes once compiled) is nothing but the deterministic version of the protected virtual Object::Finalize method (or finalizer, the !C syntax). The task of the first is to release all memory-expensive or systemwide-limited resources: big in-memory arrays, such as System::Drawing::Image; network or file handles, such as database connections. But you must know that in .NET you CANNOT DIRECTLY DESTROY AN OBJECT, that is, cannot do anything like free(ptr) or delete ptr, because all allocation and freeing of memory is under control of the garbage collector. What Dispose (~C) allows you to do is to release unmanaged resources and/or big managed objects as soon as possible, thus allowing the GC to collect them earlier in case of need or just rutinary collections. The finalizer (!C) should just be a safety measure for releasing unmanaged objects that are not fully under the GC control, because all managed items will get automatically collected (however, it is still better to release as many as possible as soon as possible). The usual practice is what I showed above: the destructor does whatever it needs and then supresses the finalizer invocation (to avoid overhead), while the finalizer, if called, just calls the destructor. The disposed variable is the only one used after calling Dispose, because each and every method and property in the object should throw an ObjectDisposedException if called after ~C. Habbit 11:18, 17 July 2006 (UTC)
- For god's sake we must explain all this madness in the article --euyyn 22:37, 26 July 2006 (UTC)
- The article perhaps needs to explain why it isn't madness. Since managed classes are garbage collected, the GC is responsible for their memory and you can't decide to delete objects off your own bat - this isn't madness. What C++/CLI provides is a mechanism for deterministic releasing of resources held by managed classes. By resources I mean objects in the unmanaged world which aren't known about by the GC and so don't influence its collection strategy. For example, unmanaged objects in memory such as file handles, database connections... etc. —Preceding unsigned comment added by 83.244.199.2 (talk) 15:43, 20 May 2008 (UTC)
- For god's sake we must explain all this madness in the article --euyyn 22:37, 26 July 2006 (UTC)
Lacks generic explanation/overview
[edit]The article barely (or not at all) explains WHAT is CLI, how it is different from C++, the relation to .NET, etc. Most of it is a list of technical specs, which is not very useful to most people. 88.155.88.39 23:17, 15 February 2007 (UTC)
strange focus
[edit]It's really strange that the first code examples in this page are of the older managed C++ and not of C++\CLI. Shouldn't the document simply lead in with C++\CLI, and have a History section later?
I'd like to know when C++/CLI was first introduced. That would be something useful to add to this article. Zobdos (talk) 13:02, 17 September 2008 (UTC)
- I completely agree that in that the continued inclusion of Managed C++ examples (especially being ahead of the CLI examples) are thoroughly confusing. My vote is to move the MC++ examples elsewhere. Todd (talk) 10:33, 18 November 2011 (UTC)
Static operator overloading
[edit]I find the sentence "Of course, operator overloading is static, as is and always should be, not only when writing managed code" a bit strange. It sounds very biased and taking things for granted even though there might not be an absolute truth to it. Does all programming languages that support operator overloading use static overloading? Can somebody give a reference as to why static operator overloading is always the best? TobiasPersson (talk) 19:32, 27 November 2007 (UTC)
- One reason operator overloading is static is that, in the case of operator== you could write "bool xEqualsY= x == y;" where x was null. In this case if == were not static, you'd be calling the operator implementation on null and would get a null reference exception. —Preceding unsigned comment added by 83.244.199.2 (talk) 15:47, 20 May 2008 (UTC)
- Yes, I think I've seen this example before and it do makes sense. Nevertheless, the phrasing seems less neutral than I prefer and there are languages that do allows non-static operator overloading, so I would suggest that someone more capable with the subject reformulates the text in the section. TobiasPersson (talk) 13:54, 22 July 2008 (UTC)
- I understand the logic in the argument but I must disagree. Having an operator throw an exception for the above example is precisely what should happen. Consider what it means to use operator==(); you want to compare the *contents* of 2 locations in memory. If one of those locations is NULL, then the comparison cannot be made and is itself invalid. As for the comment, it should be reduced to a statement of fact only, i.e. "Operator overloading is static for managed code." 161.165.196.84 (talk) 21:40, 8 September 2009 (UTC)
Article should start with standalone description
[edit]First there should be a standalone description explaining how it differs from standard C++. Then at the end there can be a section on how it differs from MC++. —Preceding unsigned comment added by Dave Yost (talk • contribs) 20:24, 17 March 2010 (UTC)
Goal or Market of the language
[edit]I think the focus is a bit too much on syntax of the language. I would suggest to add a little phrase on when to use it over tradition C++ and .NET most common language C#. Something like: The language C++/CLI makes it easy to write code that needs to inter operate with unmanaged code. It is especially used for marshaling between managed and unmanaged types. Other languages need to use the P/Invoke marshaller which has limited capabilities compared to what C++/CLI can do. If this is not the goal of your project, C# for making .NET programs or C++ for making the native bound executables would be a better option. —Preceding unsigned comment added by AntonHogervorst (talk • contribs) 14:29, 22 July 2010 (UTC)
Code that is both standard and type-safe
[edit]From the article: "Every * becomes a ^, every & becomes an %". Has a reliable source described a way to write C++ code that compiles both as standard C++ (for use on non-Microsoft platforms) and as verifiably type-safe C++/CLI (for use on .NET platforms with tight security policies)? --Damian Yerrick (talk | stalk) 05:53, 7 February 2011 (UTC)
Well, you might use a code generator ;-)
In other words, no, I´m sorry, that´s not possible. I don´t know whether it might have been in corner cases with managed extensions for C++, but it sure ain´t with C++/CLI. The distinction between * and ^ is simply an expression of the fact that it makes a great difference whether something points to a managed or an unmanaged object... so, even if the distincion wasn´t made in the syntax, it would be hardly possible to write code that REALLY doesn´t have to care about that difference. Except in aforementioned corner cases, of course... :-)
Sbohmann (talk) 17:54, 27 May 2011 (UTC)
- Dunno if a reliable sourece has described it but presumablly you could use #define to choose which structures to use at compile time. You would have to be very careful to write code that works correctly either way. Still I think it could be done if you made the code use "managed pointers" in C++/CLI and shared_ptr/weak_ptr in regular C++. 130.88.108.187 (talk) 15:08, 27 January 2012 (UTC)
Comments for code snippets
[edit]I for one would appreciate comments in the first code snippet https://en.wikipedia.org/wiki/C%2B%2B/CLI#Tracking_references illustrating where the C++/CLI diverges feature-wise from C++, and also hammering home the point of the snippet. For example at the end of the "for each" line a comment saying: "// Tracking reference resolves to element of 'arr'. Illegal in plain C++. " (I am not a C++/CLI user just familiarizing myself.)