The first subject I want to talk about, is what I consider to be the most important subject of all, when it comes to writing software - memory management.
Why is memory management so important? Because I would estimate that 90% of all bugs, crashes and security holes that occur in software are related to memory management. It is a tricky subject to get right. Memory management is the process of allocating memory, using it and freeing it when you are done with it. A well written program uses as little memory as possible. It should not 'hog' the machine. This is one area, where I feel that C# fails, despite admirable efforts to succeed.
In C++, you are completely on your own when it comes to memory management. You tell the program exactly when to allocate the memory and exactly when to free it. This is the simplest and most straight-forward way to do things. It is also, unfortunately, the most error-prone. As programs get larger, and more complicated, you tend to lose track of where memory was allocated, how big it is, and where you need to delete it. This leads to frequent 'memory leaks' where you allocate memory and forget to delete it. This memory is then essentially lost for the remainder of the life of the program. Over time, these memory leaks can add up causing losses of performance or potentially causing the program to crash due to an out of memory condition. Plus, many programmers are unaware of the fact that in C++, there are two different ways to delete memory. You use one technique to delete a single object, and another techique to delete an array of objects. If you use the wrong one, you can potentially leak memory or even cause a crash. While this way of handling memory management is prone to errors, it also gives you great control. If you are able to control exactly when memory is allocated and when it is deleted, you can write your program to use memory very efficiently. This is a good thing.
In C#, things work very differently. In C#, you allocate objects and never delete them! The idea here is that the C# runtime will keep track of when an object is used and when it isn't. When the object is no longer used, it automatically deletes the memory for you. This design was intended to solve the problem of forgetting to delete the memory and having memory leaks all over the program. It has been my experience, however, that this feature has had the opposite effect. It's lead to more of what I would consider 'memory leaks'.
The problem with the way the C# runtime deletes memory is that it doesn't delete the memory immediately once it determines that the memory is no longer being used. This memory is instead placed in a pool of memory to be deleted later, whenever the runtime decides to do it. While this memory is in this pool, it is effectively 'leaked'. It's still wasting memory, even though it's not being used by the application. There is no way to know when this memory will be cleaned up by the runtime and thus no way to know at any given time, exactly how much memory your program is using! If your program is creating many temporary objects, this can lead to unusually high usage of memory by your program. This is wasteful in my opinion.
The other problem with the C# way of deleting memory is that it leads programmers to develop very dangerous habits. If you learned to program on a language like C#, you've developed the habit of just going around happily creating objects and never cleaning up after yourself. This can be a very dangerous habit to have if you suddenly have to switch to a language like C++ or Objective-C where this is your responsibility.