I'm trying to familiarize myself with delegates and on http://msdn.microsoft.com/en-us/library/aa288459(v=vs.71).aspx, I'm reading:
"Unlike function pointers in C or C++, delegates are object-oriented, type-safe, and secure."
a mean, I do have C++ background, and somewhat cannot see how to understand the word "unlike" there. What do they mean by delegates are object-oriented and C++ fnc pointers are not? Same for type safe, and secure.
Anyone could show few examples and contra-examples?
Thanks.
A delegate does quite a bit more than a function pointer. It not only stores the function address, it also stores a reference to the target object. Unlike a C++ method pointer. So it is simple to use to call an instance method. That takes care of the "object-oriented" claim.
A bit down-hill from there, but type safety is ensured by the compiler verifying that the function signature exactly matches the delegate type when you assign the delegate. Which is no different in C++ but there's no way to cast a mismatch away. Another possible security aspect is that the object reference held by the delegate object is visible to the garbage collector. So you can never call an instance method on a deleted object.
Related
OpenTK does bindings to OpenGL by first defining a delegate with a matching signature to some target C function:
[System.Security.SuppressUnmanagedCodeSecurity()]
internal delegate void Uniform1f(Int32 location, Single v0);
internal static Uniform1f glUniform1f;
And then it assigns a value to glUniform1f that is returned from a platform specific OpenGL GetProcAddress function.
If I don't use OpenTK's approach, and instead just pinvoke the function using DllImport, will my code perform slower? (in otherwords, is there any performance benefit for using a delegate).
No, if anything, there will be a performance hit (although incredibly insignificant in most cases) because you are using a delegate.
Remember, a delegate is a reference to a method. Every time it's called, that reference has to be derefrenced. Compare this to a method call that's compiled into your code; the runtime knows exactly where it has to go as the method reference is baked into the IL.
Note that delegate performance has improved significantly since .NET 3.0. With the introduction of LINQ, delegates were going to be used extremely heavily, and with them being that ubiquitous, they have to be fast.
A possible reason you are seeing delegates being used is because the DLL that contains the unmanaged code needs to be determined at runtime (perhaps because of naming issues, processor-specific builds distributed together under different names, etc.).
In this case, an call is made to the unmanaged LoadLibrary Windows API function, followed by a call to the unmanaged GetProcAddress Windows API function.
Once the function poitner has been retreived, it is passed to the GetDelegateForFunctionPointer method on the Marshal class in order to get the delegate.
Sorry for being confused, at C++ I know to return local variable's reference or pointers can cause bad_reference exception. I am not sure how it is in C# ?
e.g
List<StringBuilder> logs = new List<StringBuilder>();
void function(string log)
{
StringBuilder sb = new StringBuilder();
logs.Add(sb);
}
at this function a local object is created and stored in a list, is that bad or must be done in another way. I am really sorry for asking this, but I am confused after coding C++ for 2 months.
Thanks.
Your C# code doesn't return an object reference so it doesn't match your concern. It is however a problem that doesn't exist in C#. The CLR doesn't let you create objects on the stack, only the heap. And the garbage collector makes sure that object references stay valid.
In C#, the garbage collector manages all the (managed) objects you create. It will not delete one unless there are no longer any references to it.
So that code is perfectly valid. logs keeps a reference to the StringBuilder. The garbage collector knows this, so it will not clean it up even after the context in which it was originally created goes out of scope.
In C# object lifecycle is managed for you by the CLR; compared to C++ where you have to match each new with a delete.
However in C# you can't do
void fun()
{
SomeObject sb(10);
logs.Add(sb);
}
i.e. allocating on the stack you have to use new - so in this respect both C# and C++ work similarly - except when it comes to releasing / freeing the object reference.
It is still possible to leak memory in C# - but it's harder than in C++.
There's nothing wrong with the code you've written. This is mostly because C#, like any .NET language, is a "managed" language that does a lot of memory management for you. To get the same effect in C++ you would need to explicitly use some third-party library.
To clear up some of the basics for you:
In C#, you rarely deal with "pointers" or "references" directly. You can deal with pointers, if you need to, but that is "unsafe" code and you really avoid that kind of thing unless you know what you're doing. In the few cases where you do deal with references (e.g. ref or out parameters) the language hides all the details from you and lets you treat them as normal variables.
Instead, objects in C# are defined as instances of reference types; whenever you use an instance of a reference type, it is similar to using a pointer except that you don't have to worry about the details. You create new instances of references types in C# in the same way that you create new instances of objects in C++, using the new operator, which allocates memory, runs constructors, etc. In your code sample, both StringBuilder and List<StringBuilder> are reference types.
The key aspect of managed languages that is important here is the automatic garbage collection. At runtime, the .NET Framework "knows" which objects you have created, because you're always creating them from it's own internally-managed heap (no direct malloc or anything like that in C#). It also "knows" when an object has gone completely out of scope -- when there are no more references to it anywhere in your program. Once that happens, the runtime is able to free the memory whenever it wants to, typically when it starts to run low on free memory, and you never have to do it. In fact, there is no way in C# to explicitly destroy a managed object (though you do have to clean up unmanaged resources if you use them).
In your example, the runtime knows that you've created a StringBuilder and put it into a List<>; it will keep track of that object, and as long as it's in the List<> it will stick around. Once you either remove it from the List<>, or the List<> itself goes away, the runtime will automatically clean up the StringBuilder for you.
I'm trying to write a pinvoke for the ITaskTrigger::GetTriggerString method (defined at http://msdn.microsoft.com/en-us/library/windows/desktop/aa381866(v=vs.85).aspx). If you look at the page, it says that the caller of the method is responsible for freeing the memory (via CoTaskMemFree) of the LPWSTR referenced via the first argument. While I could do that manually in .NET or could write my custom marshaler using ICustomMarshaler, I was wondering if using the MarshalAs(UnmanagedType.LPWStr) attribute for that particular argument will free the memory appropriately.
Can anyone provide some insight?
First things first: you're talking about COM Interop here (ITaskTrigger is a COM interface), not P/Invoke. There are different interop rules for the two, so it's important to keep them straight. For example, you'll need to define C# interop wrappers for the entire interface, not just the method you want. These should get you started: pinvoke.net
The short answer is, you're in luck, becase the CLR should take care of things properly for you.
The longer answer involves the different types of marshalling the COM interop code does, depending on the parameter types, directions, and what attributes you add to your interop signatures.
In this case, the parameter type you will get on the call is an "out string" parameter, with a MarshalAs(UnmanagedType.LPWSTR) attribute. When a COM server exposes a call that has an "out" parameter of LPWSTR string type, assuming the server is keeping up its end of the deal, it will allocate a memory buffer with CoTaskMemAlloc() and return it to you. (If it was a different string type, like a BSTR, the specific memory allocation call might be different, but the basic concept is the same.) At this point, you are responsible for cleaning up that memory when you no longer need it, using the matching CoTaskMemFree() call.
This is a special type of operation called a "reference change": the parameter you are sending in is already a reference parameter, but the COM server is going to replace it with a different reference. A good explanation for this process is found in the "Memory Ownership" section of this MSDN magazine article. As you can see from that article, when the CLR receives data back from an "out" parameter on a reference type, it recognizes that it is taking responsibility for freeing that memory. While marshaling that call back to managed code, it uses the MarshalAs attribute to determine that this is a LPWSTR string-type pointer in COM, and that it should therefore have been allocated using CoTaskMemAlloc(). After creating a managed string out of the data, it will call CoTaskMemFree() on the original buffer on your behalf. The data you get back will be fully managed and you won't have to deal with any ownership problems.
Assume someClass is a class defined in C# with some method int doSomething(void), and for simplicity, providing a constructor taking no arguments. Then, in C#, instances have to be created on the gc heap:
someClass c; // legit, but only a null pointer in C#
// c->doSomething() // would not even compile.
c = new someClass(); // now it points to an instance of someclass.
int i = c->doSomething();
Now, if someClass is compiled into some .Net library, you can also use it in C++/CLI:
someClass^ cpp_gcpointer = gcnew someClass();
int i = cpp_gcpointer->doSomething();
That easy! Nifty! This is of course assuming a reference to the .Net library has been added to the project and a corresponding using declaration has been made.
It is my understanding that this is the precise C++/CLI equivalent of the previous C# example (condensed to a single line, this is not the point I'm interested in). Correct? (Sorry, I'm new to the topic)
In C++, however, also
someClass cpp_cauto; // in C++ declaration implies instantiation
int i = cpp_cauto.doSomething();
is valid syntax. Out of curiosity, I tried this today. A colleague, looking over my shoulder, was willing to bet it would not even compile. He would have lost the bet. (This is still the class from the C# assembly). Actually it produces also the same result i as the code from the previous examples.
Nifty, too, but -- uhmm -- what exactly is it, what is created here? My first wild guess was that behind my back, .Net dynamically creates an instance on the gc heap and cpp_auto is some kind of wrapper for this object, behaving syntactily like an instance of class someClass. But then I found this page
http://msdn.microsoft.com/en-us/library/ms379617%28v=vs.80%29.aspx#vs05cplus_topic2
This page seems to tell me, that (at least, if someClass were a C++ class) cpp_auto is actually created on the stack, which, to my knowledge, would be the same behaviour you get in classical C++. And something you cannot do in C# (you can't, can you?). What I'd like to know: is the instance from the C# assembly also created on the stack? Can you produce .Net binaries in C++ with class instances on the stack which you cannot create in C#? And does this possibly may even give you a perfomance gain :-) ?
Kind regards,
Thomas
The link you referenced explains this in detail:
C++/CLI allows you to employ stack semantics with reference types. What this means is that you can introduce a reference type using the syntax reserved for allocating objects on the stack. The compiler will take care of providing you the semantics that you would expect from C++, and under the covers meet the requirements of the CLR by actually allocating the object on the managed heap.
Basically, it's still making a handle to the reference type on the managed heap, but automatically calls Dispose() on IDisposable implementations when it goes out of scope for you.
The object instance, however, is still effectively allocated via gcnew (placed on the managed heap) and collected by the garbage collector. This, too, is explained in detail:
When d goes out of scope, its Dispose method will be called to allow its resources to be released. Again, since the object is actually allocated from the managed heap, the garbage collector will take care of freeing it in its own time.
Basically, this is all handled by the compiler to make the code look and work like standard C++ stack allocated classes, but its really just a compiler trick. The resulting IL code is still doing managed heap allocations.
Will using GetComInterfaceForObject and passing the returned IntPtr to unmanaged code keep the managed object from being moved in memory? Or does the clr somehow maintain that ptr? Note that the unmanaged code will use this for the lifetime of the program, and I need to make sure the managed object is not being moved by the GC.(At least I think that's right?)
EDIT - Alright I found some info and I am thinking that this may be the answer. It deals with delegates, but I would have to believe calling GetComInterfaceForObject does something along the same lines.
Source of the Following text
"Managed Delegates can be marshaled to unmanaged code,
where they are exposed as unmanaged function pointers. Calls on those
pointers will perform an unmanaged to managed transition; a change in
calling convention; entry into the correct AppDomain; and any necessary
argument marshaling. Clearly the unmanaged function pointer must refer to a
fixed address. It would be a disaster if the GC were relocating that! This
leads many applications to create a pinning handle for the delegate. This
is completely unnecessary. The unmanaged function pointer actually refers
to a native code stub that we dynamically generate to perform the transition
& marshaling. This stub exists in fixed memory outside of the GC heap.
However, the application is responsible for somehow extending the lifetime
of the delegate until no more calls will occur from unmanaged code. The
lifetime of the native code stub is directly related to the lifetime of the
delegate. Once the delegate is collected, subsequent calls via the
unmanaged function pointer will crash or otherwise corrupt the process. In
our recent release, we added a Customer Debug Probe which allows you to
cleanly detect this all too common bug in your code. If you havent
started using Customer Debug Probes during development, please take a look!"
As your edit states (about delegates), your managed object doesn't need to be pinned, since GetComInterfaceForObject returns a "pinned" pointer that calls through to the correct managed object. However, you will need to make sure that the managed object lives for as long as the COM clients are using the unmanaged pointer to it.