Date post: | 23-Dec-2014 |
Category: |
Software |
Upload: | richard-thomson |
View: | 534 times |
Download: | 4 times |
C TRAPS AND PITFALLS FOR C++
PROGRAMMERS
void *pointers
Loses all type information!
Should be avoided when possible
Make the C++ type system work for you, don’t subvert it
Interfaces to C libraries may require it
C Style Casts
C style casts:do not communicate the intent of the castcan give the wrong answer
Use relevant C++ casting operatorcommunicates the intent of the castgives the right answer
Use constructor syntax for valuesint(floatFn()) instead of (int) floatFn()
const_cast<T>(expression) const_cast<T> changes the const or
volatile qualifier of its argument With T const *p
use const_cast<T*>(p) instead of ((T *) p) Declare class members mutable if they
need to be updated from a const method Writing through a reference or pointer
stripped of its constness may cause undefined behavior!
static_cast<T>(expression) Converts to type T, purely based on the
types present in expression. Use static_cast<T> when:
you intend that the cast does not require any run-time type information
Cast enums to a numeric type (int, float, etc.)Cast from void pointer to T pointerCast across the class hierarchy with multiple
inheritance; see http://www.sjbrown.co.uk/2004/05/01/always-use-static_cast/
dynamic_cast<T>(expression) Requires RTTI to be enabled Only for pointers or references Returns 0 when object is not a T Resolves multiple inheritance properly
reinterpret_cast<T>
The most evil of cast operators Subverts the type system completely Should only be needed when dealing
with C style APIs that don’t use void pointers
Memory Allocation
Any call to new or new[] should only appear in a constructor
Any call to delete or delete[] should only appear in a destructor
Encapsulate memory management in a class
More on new and delete new/new[]
does’t return 0 when memory is exhaustedthrows bad_allocVC6 did it wrong; VS2005/gcc does it rightNo need to check for zero pointer returned
delete/delete[]Deleting a zero pointer is harmlessNo need to check for zero pointer before calling
Always match new[] with delete[] and scalar new with scalar delete
Resource Acquisition
Memory is just one kind of resource Others:
critical sectionthread locketc
Treat identically to memory:acquire resource in c’torrelease resource in d’tor
RAII – Resource Acquisition Is Initialization
Exceptions
Using RAII gives you exception safe code for free
Manual management of resources requires try/catch blocks to ensure no memory leaks when an exception is thrown
std::auto_ptr<T>
Takes ownership of whatever pointer assigned to it
~auto_ptr() calls delete on the pointer release() returns the pointer and releases
ownership Calls scalar delete; doesn’t work for arrays Use for temporary buffers that are
destroyed when going out of scope or are explicitly assigned to something else on success
std::vector<T>
Dynamically resizable array Great for fixed-size buffers you need to
create for C APIs when the size of the buffer is determined at runtime.
Use for temporary arrays of objects If used as an array of pointers, it doesn’t
call delete on each pointer
boost::shared_ptr<T>
Reference counted pointer When reference count reaches zero,
delete is called on the underlying pointer Doesn’t guard against cycles Can be good when used carefully, but
can be bad when used excessively. It becomes hard to identify the lifetime of resources
See boost docs for more
boost::ptr_vector<T>
Boost container similar to std::vector<T>, but calls delete on each element when it is destroyed
See boost docs for more
C style strings Don’t use them! Huge source of bugs. Use a string class:
Qt’s QStringC++ std::stringC++ std::basic_string<TCHAR>wxWidgets wxString
Pass string classes by const reference Return string classes by value or through
reference argument Use std::string::c_str() to talk to C APIs
Use of void
Don’t use void argument lists:Use void foo() instead of void foo(void)
Don’t use void pointersIt completely subverts the type system,
leading to type errors
Callbacks C code can only call back through a function
pointer. A void pointer context value is usually passed along to the callback
C++ code uses an interface pointer or reference to communicate to its caller. No need to supply a context value as the interface pointer is associated with a class that will hold all the context.
Use interfaces instead of function pointers for callbacks
#define Use enums to define groups of related
integer constants Use static const class members to define
integer or floating-point values. Declare them in the .h, define them in the .cpp
Use inline functions or methods for small blocks of repeated code
Use templates as a way to write type safe macros that expand properly or generate a compiler error
Static Polymorphism
Static polymorphism exploits similarities at compile time
Dynamic polymorphism exploits similarities at runtime
Static polymorphism implemented with templates
Dynamic polymorphism implemented with virtual methods on classes
#if, #else, #endif
Used to express static variation in code When compiled one way, you get one
variation; when compiled the other way, you get the other variation
Better expressed through a template class that expresses the two variations as specifics of arguments to the template
Keeps syntactic checking on for both variations all the time