I'm currently teaching myself C++. I'm very proficient at C#, and was wondering which common practices in C# can lead to difficulties in C++, and what a C++ programmer should do instead.
The first and foremost, you must learn RAII: Resource Acquisition Is Initialization
Make sure if you use
new, then don't forget to use
deletein your program. Don't mix
mallocare not interchangeable, nor are
free. As in C#, you don't write destructor (usually), so in C++ you specifically need to learn how to use destructor effectively to free memory, and other resources!
Must learn what is sequence points, undefined-behavior, unspecified-behavior, implementation-defined behavior in C++. As C# doesn't have these concepts, that means you've never heard these terms while programming in C#, so it's very very very likely that you'll write C++ code (such as
i+=++i) whose behavior is not well-defined. So I would recommend you to read these topics:
- Read items from Effective C++ Series by Scott Meyers. After them, read also Exceptional C++ Series by Herb Sutter.
PS: Since I talked about new, delete, raw memory etc, then let me add an interesting difference between C++ and C# :
this is a pointer, while in C#
this is a reference!
The most fundamental one is of course related to the lack of a garbage collector:
newany more than necessary. Understand the RAII idiom: allocate your objects on the stack (without using
new), and let their destructors take care of cleaned up allocated memory for you. Or use smart pointers to handle some of this for you.
Other than that, I'd say there are some stylistic issues you should get used to. C# is still, despite its flirtation with functional programming, an OOP language.
C++ is a multi-paradigm language, and in modern C++, OOP just doesn't play a very big role. You should definitely look into generic programming, though. Understand how to use the STL (the data structures, iterators and algorithms in the standard library). And feel just a bit dirty when you write a virtual function.
The biggest problem I've seen is the tendency to new objects all over the place and use them on the heap. Sure, they may take a lot of care deleting them as there's no GC, but the problem is allocating on the heap in the first place. C++ works better putting stuff on the stack and copying it about. If you do still need a single shared object, use shared_ptr to contain it.
Mind you, this isn't exclusive to C# devs, I've seen a a few web devs do the same kind of thing.
Garbage collection is a big one, but if you use smart pointers you can avoid most of the trouble with that.
A more pervasive issue is that of exception safety. This isn't so much a C# habit that will get you in trouble, but a lack of one. In C#, you get safety with
using blocks and
finally handlers. C++ has neither. What you have is a technique called RAII (resource acquisition is initialization), where classes are carefully designed so that their destructors clean things up. So rather than use a
using block to open a file, you'll stack-allocate the file object and the destructor will flush and close the file. It takes care to design and use classes in this way, but once you form the habit your code can be pretty safe. It's just a different approach. In general, the fact that C++ has stack allocation of objects will necessitate some adjustment.
Be wary of
string types in C++, they have grown up from many years of (bitter) experience and there are different types. In C# they're all Unicode (I forget the encoding), but in C++ a
char is usually dependent on the system's code page. For example, US-English Windows uses a code page of Windows 1252 by default for non unicode programs. Code pages are difficult to manage and error prone so use
wchar_t and the STL's
std::wstring. Also be aware that the size of
wchar_t is different between different compilers. Many Linux based C++ compilers use a different character size and the advice is different again! See https://stackoverflow.com/questions/4588302/why-isnt-wchar-t-widely-used-in-code-for-linux-related-platforms for more info.
Be aware of the scope of variables and when they will be destructed. It is generally bad practice to do
return new object() as the caller might not realize they need to clean up the return value.
Learn about move semantics - they can help a lot with RAII. I'm not aware of an equivalent in C#
Understand what an opaque pointer is. If you're using the Windows API you'll come across a lot of these in the form of
Be wary of storing lists (e.g.
std::deque) of objects which can be inherited as this can lead to slicing where the inherited part of the class is sliced off so only the declared type is left.