| |
| C++ Standard Library Style Guidelines DRAFT 2001-01-15 |
| ------------------------------------- |
| |
| This library is written to appropriate C++ coding standards. As such, |
| it is intended to precede the recommendations of the GNU Coding |
| Standard, which can be referenced here: |
| |
| http://www.gnu.org/prep/standards_toc.html |
| |
| ChangeLog entries for member functions should use the |
| classname::member function name syntax as follows: |
| |
| 1999-04-15 Dennis Ritchie <dr@att.com> |
| |
| * src/basic_file.cc (__basic_file::open): Fix thinko in |
| _G_HAVE_IO_FILE_OPEN bits. |
| |
| Notable areas of divergence from what may be previous local practice |
| (particularly for GNU C) include: |
| |
| 01. Pointers and references |
| char* p = "flop"; |
| char& c = *p; |
| -NOT- |
| char *p = "flop"; // wrong |
| char &c = *p; // wrong |
| |
| Reason: In C++, definitions are mixed with executable code. Here, |
| p is being initialized, not *p. This is near-universal |
| practice among C++ programmers; it is normal for C hackers |
| to switch spontaneously as they gain experience. |
| |
| 02. Operator names and parentheses |
| operator==(type) |
| -NOT- |
| operator == (type) // wrong |
| |
| Reason: The == is part of the function name. Separating |
| it makes the declaration look like an expression. |
| |
| 03. Function names and parentheses |
| void mangle() |
| -NOT- |
| void mangle () // wrong |
| |
| Reason: no space before parentheses (except after a control-flow |
| keyword) is near-universal practice for C++. It identifies the |
| parentheses as the function-call operator or declarator, as |
| opposed to an expression or other overloaded use of parentheses. |
| |
| 04. Template function indentation |
| template<typename T> |
| void |
| template_function(args) |
| { } |
| -NOT- |
| template<class T> |
| void template_function(args) {}; |
| |
| Reason: In class definitions, without indentation whitespace is |
| needed both above and below the declaration to distinguish |
| it visually from other members. (Also, re: "typename" |
| rather than "class".) T often could be int, which is |
| not a class. ("class", here, is an anachronism.) |
| |
| 05. Template class indentation |
| template<typename _CharT, typename _Traits> |
| class basic_ios : public ios_base |
| { |
| public: |
| // Types: |
| }; |
| -NOT- |
| template<class _CharT, class _Traits> |
| class basic_ios : public ios_base |
| { |
| public: |
| // Types: |
| }; |
| -NOT- |
| template<class _CharT, class _Traits> |
| class basic_ios : public ios_base |
| { |
| public: |
| // Types: |
| }; |
| |
| 06. Enumerators |
| enum |
| { |
| space = _ISspace, |
| print = _ISprint, |
| cntrl = _IScntrl |
| }; |
| -NOT- |
| enum { space = _ISspace, print = _ISprint, cntrl = _IScntrl }; |
| |
| 07. Member initialization lists |
| All one line, separate from class name. |
| |
| gribble::gribble() |
| : _M_private_data(0), _M_more_stuff(0), _M_helper(0); |
| { } |
| -NOT- |
| gribble::gribble() : _M_private_data(0), _M_more_stuff(0), _M_helper(0); |
| { } |
| |
| 08. Try/Catch blocks |
| try |
| { |
| // |
| } |
| catch (...) |
| { |
| // |
| } |
| -NOT- |
| try { |
| // |
| } catch(...) { |
| // |
| } |
| |
| 09. Member functions declarations and definitions |
| Keywords such as extern, static, export, explicit, inline, etc |
| go on the line above the function name. Thus |
| |
| virtual int |
| foo() |
| -NOT- |
| virtual int foo() |
| |
| Reason: GNU coding conventions dictate return types for functions |
| are on a separate line than the function name and parameter list |
| for definitions. For C++, where we have member functions that can |
| be either inline definitions or declarations, keeping to this |
| standard allows all member function names for a given class to be |
| aligned to the same margin, increasing readibility. |
| |
| |
| 10. Invocation of member functions with "this->" |
| For non-uglified names, use this->name to call the function. |
| |
| this->sync() |
| -NOT- |
| sync() |
| |
| Reason: Koenig lookup. |
| |
| 11. Namespaces |
| namespace std |
| { |
| blah blah blah; |
| } // namespace std |
| |
| -NOT- |
| |
| namespace std { |
| blah blah blah; |
| } // namespace std |
| |
| 12. Spacing under protected and private in class declarations: |
| space above, none below |
| ie |
| |
| public: |
| int foo; |
| |
| -NOT- |
| public: |
| |
| int foo; |
| |
| 13. Spacing WRT return statements. |
| no extra spacing before returns, no parenthesis |
| ie |
| |
| } |
| return __ret; |
| |
| -NOT- |
| } |
| |
| return __ret; |
| |
| -NOT- |
| |
| } |
| return (__ret); |
| |
| |
| 14. Location of global variables. |
| All global variables of class type, whether in the "user visable" |
| space (e.g., cin) or the implementation namespace, must be defined |
| as a character array with the appropriate alignment and then later |
| re-initialized to the correct value. |
| |
| This is due to startup issues on certain platforms, such as AIX. |
| For more explanation and examples, see src/globals.cc. All such |
| variables should be contained in that file, for simplicity. |
| |
| 15. Exception abstractions |
| Use the exception abstractions found in functexcept.h, which allow |
| C++ programmers to use this library with -fno-exceptions. (Even if |
| that is rarely advisable, it's a necessary evil for backwards |
| compatibility.) |
| |
| 16. Exception error messages |
| All start with the name of the function where the exception is |
| thrown, and then (optional) descriptive text is added. Example: |
| |
| __throw_logic_error(__N("basic_string::_S_construct NULL not valid")); |
| |
| Reason: The verbose terminate handler prints out exception::what(), |
| as well as the typeinfo for the thrown exception. As this is the |
| default terminate handler, by putting location info into the |
| exception string, a very useful error message is printed out for |
| uncaught exceptions. So useful, in fact, that non-programmers can |
| give useful error messages, and programmers can intelligently |
| speculate what went wrong without even using a debugger. |
| |
| The library currently has a mixture of GNU-C and modern C++ coding |
| styles. The GNU C usages will be combed out gradually. |
| |
| Name patterns: |
| |
| For nonstandard names appearing in Standard headers, we are constrained |
| to use names that begin with underscores. This is called "uglification". |
| The convention is: |
| |
| Local and argument names: __[a-z].* |
| |
| Examples: __count __ix __s1 |
| |
| Type names and template formal-argument names: _[A-Z][^_].* |
| |
| Examples: _Helper _CharT _N |
| |
| Member data and function names: _M_.* |
| |
| Examples: _M_num_elements _M_initialize () |
| |
| Static data members, constants, and enumerations: _S_.* |
| |
| Examples: _S_max_elements _S_default_value |
| |
| Don't use names in the same scope that differ only in the prefix, |
| e.g. _S_top and _M_top. See BADNAMES for a list of forbidden names. |
| (The most tempting of these seem to be and "_T" and "__sz".) |
| |
| Names must never have "__" internally; it would confuse name |
| unmanglers on some targets. Also, never use "__[0-9]", same reason. |
| |
| -------------------------- |
| |
| [BY EXAMPLE] |
| |
| #ifndef _HEADER_ |
| #define _HEADER_ 1 |
| |
| namespace std |
| { |
| class gribble |
| { |
| public: |
| // ctor, op=, dtor |
| gribble() throw(); |
| |
| gribble(const gribble&); |
| |
| explicit |
| gribble(int __howmany); |
| |
| gribble& |
| operator=(const gribble&); |
| |
| virtual |
| ~gribble() throw (); |
| |
| // argument |
| inline void |
| public_member(const char* __arg) const; |
| |
| // in-class function definitions should be restricted to one-liners. |
| int |
| one_line() { return 0 } |
| |
| int |
| two_lines(const char* arg) |
| { return strchr(arg, 'a'); } |
| |
| inline int |
| three_lines(); // inline, but defined below. |
| |
| // note indentation |
| template<typename _Formal_argument> |
| void |
| public_template() const throw(); |
| |
| template<typename _Iterator> |
| void |
| other_template(); |
| |
| private: |
| class _Helper; |
| |
| int _M_private_data; |
| int _M_more_stuff; |
| _Helper* _M_helper; |
| int _M_private_function(); |
| |
| enum _Enum |
| { |
| _S_one, |
| _S_two |
| }; |
| |
| static void |
| _S_initialize_library(); |
| }; |
| |
| // More-or-less-standard language features described by lack, not presence: |
| # ifndef _G_NO_LONGLONG |
| extern long long _G_global_with_a_good_long_name; // avoid globals! |
| # endif |
| |
| // Avoid in-class inline definitions, define separately; |
| // likewise for member class definitions: |
| inline int |
| gribble::public_member() const |
| { int __local = 0; return __local; } |
| |
| class gribble::_Helper |
| { |
| int _M_stuff; |
| |
| friend class gribble; |
| }; |
| } |
| |
| // Names beginning with "__": only for arguments and |
| // local variables; never use "__" in a type name, or |
| // within any name; never use "__[0-9]". |
| |
| #endif /* _HEADER_ */ |
| |
| |
| namespace std |
| { |
| template<typename T> // notice: "typename", not "class", no space |
| long_return_value_type<with_many, args> |
| function_name(char* pointer, // "char *pointer" is wrong. |
| char* argument, |
| const Reference& ref) |
| { |
| // int a_local; /* wrong; see below. */ |
| if (test) |
| { |
| nested code |
| } |
| |
| int a_local = 0; // declare variable at first use. |
| |
| // char a, b, *p; /* wrong */ |
| char a = 'a'; |
| char b = a + 1; |
| char* c = "abc"; // each variable goes on its own line, always. |
| |
| // except maybe here... |
| for (unsigned i = 0, mask = 1; mask; ++i, mask <<= 1) { |
| // ... |
| } |
| } |
| |
| gribble::gribble() |
| : _M_private_data(0), _M_more_stuff(0), _M_helper(0); |
| { } |
| |
| inline int |
| gribble::three_lines() |
| { |
| // doesn't fit in one line. |
| } |
| } // namespace std |
| |