Herb Sutter, Andrei Alexandrescu: C++ Coding Standards (Addison Wesley, 2005) Why coding standards: - Better code quality - Faster development - Better teamwork 0. What's worth standardizing--and what isn't? - parenthesys - space or tab - Hungarian notation - one return point 1. Compile cleanly at high warning level // File: myproj/my_lambda.h -- wraps Boost's lambda.hpp // Always include this file; don't use lambda.hpp directly. // NOTE: Our build now automatically checks // "grep lambda.hpp <srcfile>". // Boost.Lambda produces noisy compiler warnings that // we know are innocuous. // When they fix it we'll remove the pragmas below, but this header // will still exist. // #pragma warning(push)// disable for this header only #pragma warning(disable:4512) #pragma warning(disable:4180) #include <boost/lambda/lambda.hpp> #pragma warning(pop) // restore original warning level - Unused parameters: // ... inside a user-defined allocator that has no use for the hint ... // warning: "unused parameter 'localityHint'" pointer allocate( size_type numObjects, const void *localityHint = 0 ) { return static_cast<pointer>( mallocShared( numObjects * sizeof(T) ) ); } // new version: eliminates warning pointer allocate( size_type numObjects, const void * /* localityHint */ = 0 ) { return static_cast<pointer>( mallocShared( numObjects * sizeof(T) )); } - Unused variable // warning: "variable 'lock' is defined but never used" void Fun() { Lock lock; // ... } // new version: probably eliminates warning void Fun() { Lock lock; lock; // ... } - missing return // warning: missing "return" int Fun( Color c ) { switch( c ) { case Red:return 2; case Green:return 0; case Blue: case Black:return 1; } } // new version: eliminates warning int Fun( Color c ) { switch( c ) { case Red:return 2; case Green:return 0; case Blue: case Black:return 1; default: assert( !"should never get here!" ); // !"string" evaluates to false return -1; } } - signed/unsigned mismatch 2. Use make 3. Use version control 4. More code-review DESIGN ====== 5. Define the role for all entity bad: realloc(), class basic_string; 6. Simplicity, clarity 7. Write scalable code - prefere dynamic over static array - know complexity of algorothms linear or linear*linear? 8. Avoid early optimalization - delay optimalizations like inline-ing 9. Avoid early pessimilation - érték szerint, ahpl ref szerint is ok. - i++ a ++i helyett - konstructor body over initialization list 10. Avoid globals 11. Hide data 12. Know when and how to code for concurrency. Summary: Thsareafedly: If your application uses multiple threads or processes, know how to minimize sharing objects where possible (see Item 10) and share the right ones safely. avoid deadlocks, livelocks, and malign race conditions Consult your target platforms' documentation for local synchronization primitives: lightweight atomic integer operations memory barriers in-process mutex cross-process mutex Prefer to wrap the platform's primitives in your own abstractions Guarantee that unshared objects are independent: Two threads can freely use different objects without any special action on the caller's part. Document what the caller needs to do to use the same object of that type in different threads: External locking: Callers are responsible for locking. if( c.empty() ) c.push_back(x); Internal locking: Each object serializes all access to itself, typically by locking every public member function, so that callers may not need to serialize uses of the object Lock-free designs, including immutability (read-only objects): No locking needed 13. RAII CODING STYLE ============ 14. Prefer compile-time errors 15. Const 16. Avoid macros Kivétel - include őrszem 17. Avoid magic numbers 18. Shrink the visibility of variables 19. Alway to initialize the variables 20. Write short functions 21. Initialization must not depend from other compilation units 22. Avoid cyclic or bilateral dependencies Ügyeljünk a függőségekre, ne ágyazzunk be olyasmit, ami helyett előzetes bevezetést is alkalmazhatnánk. 23. Make headers self supporting 24.Use internal include guards FUNCTIONS, OPERATORS ==================== What are the best ways to code for scalability? 34. Prefer composition to inheritance. Summary: Avoid inheritance taxes: Inheritance is the second-tightest coupling relationship in C++, second only to friendship Composition has important advantages over inheritance: - Greater flexibility without affecting calling code - Greater compile-time insulation, shorter compile times - Less weirdness - Wider applicability - Great robustness and safety - Less complexity and fragility Inheritance is better: - You need to override a virtual function. - Need access to a protected member. - To construct the used object before, or destroy it after, a base class. - Worry about virtual base classes. What are the elements of a rational error handling policy? How (and why) do you avoid unnecessary initialization, cyclic, and definitional dependencies? When (and how) should you use static and dynamic polymorphism together? How do you practice "safe" overriding? When should you provide a no-fail swap? Why and how should you prevent exceptions from propagating across module boundaries? Why shouldn't you write namespace declarations or directives in a header file? Why should you use STL vector and string instead of arrays? How do you choose the right STL search or sort algorithm? What rules should you follow to ensure type-safe code?