diff options
Diffstat (limited to 'ACE/docs/ACE-guidelines.html')
-rw-r--r-- | ACE/docs/ACE-guidelines.html | 1328 |
1 files changed, 1328 insertions, 0 deletions
diff --git a/ACE/docs/ACE-guidelines.html b/ACE/docs/ACE-guidelines.html new file mode 100644 index 00000000000..834b6dcaeea --- /dev/null +++ b/ACE/docs/ACE-guidelines.html @@ -0,0 +1,1328 @@ +<!-- $Id$ --> + +<html> + <head> + <title>ACE Software Development Guidelines</title> + <link rev=made href="mailto:ace-users@cs.wustl.edu"> + </head> + +<body text = "#000000" +link="#000fff" +vlink="#ff0f0f" +bgcolor="#ffffff"> + +<hr> +<h3>ACE Software Development Guidelines</h3> + +<ul> + <li><strong>General</strong><p> + <ul> + <li>Every text file must end with a newline.<p> + + <li>Use spaces instead of tabs, except in Makefiles. Emacs users + can add this to their <strong>.emacs</strong>: + + <pre>(setq-default indent-tabs-mode nil)</pre></p> + + Microsoft Visual C++ users should do the following: + + <pre> + Choose: Tools -- Options -- Tabs + Then Set: "Tab size" to 8 and "Indent size" to 2, and + indent using spaces. + </pre><p> + + <li>Do not end text lines with spaces. Emacs users can add this to + their <strong>.emacs</strong>: + + <pre>(setq-default nuke-trailing-whitespace-p t)</pre> + + <strong>Note for Microsoft Visual Studio .NET Users:</strong> + <p>There is a macro project <code>(ace_guidelines.vsmacros)</code> + located in <code>$ACE_ROOT/docs</code> that replaces tabs with spaces + and removes trailing spaces each time you save a file.</p> + + <li>Try to limit the length of source code lines to less than 80 + characters. Users with 14 inch monitors appreciate it when + reading code. And, it avoids mangling problems with email + and net news.<p> + + <li>Try to avoid creating files with excessively long names (45 characters). + Moreover, ensure that the names of generated files e.g. <code>MakeProjectCreator</code>, + <code>tao_idl</code> do not also go beyond that limit. Some operating + systems cannot handle very long file names correctly.<p> + + <li>If you add a comment to code that is directed to, or + requires the attention of, a particular individual: + <strong>SEND EMAIL TO THAT INDIVIDUAL!</strong>.<p> + + <li>Every program should have a "usage" message. It should be + printed out if erroneous command line arguments, or a + <strong><code>-?</code></strong> command line argument, are + provided to the program.<p> + + <li>A program entry point <code>main</code> can take any of the + three forms: + <p><pre> + int main (int argc, char *argv[]) + int wmain (int argc, wchar_t *argv[]) + int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) + </pre></p> + Of them, the entry point <code>main</code> always gives you + the command line argument in char strings form. The entry + point <code>wmain</code> currently can only be used under + Win32 and it returns the command line arguments in <code>wchar</code> + strings format. Defining the <code>ACE_TMAIN</code> as the + program entry point is the more portable form. The command + line arguments are given in char strings in most cases, + or <code>wchar</code> strings when <code>ACE_USES_WCHAR</code> is defined. + See <code>$ACE_ROOT/docs/wchar.txt</code> for more information + on ACE support on <code>wchar</code>.<p> + + <li>The program entry point function, in any form mentioned above, must + always be declared with arguments, <em>e.g.</em>, + <pre> + int + ACE_TMAIN (int argc, ACE_TCHAR *argv[]) + { + [...] + + return 0; + } + </pre><p> + + If you don't use the <code>argc</code> and/or <code>argv</code> + arguments, don't declare them, <em>e.g.</em>, + <pre> + int + ACE_TMAIN (int, ACE_TCHAR *[]) + { + [...] + + return 0; + } + </pre><p> + + Please declare the second argument as <code>ACE_TCHAR *[]</code> + instead of <code>ACE_TCHAR **</code> or <code>char *[]</CODE>. + Ancient versions of MSC++ + complained about <code>ACE_TCHAR **</code> and <code>char + *[]</CODE> is not Unicode-compliant.<p> + + <code>main</code> must also return 0 on successful + termination, and non-zero otherwise.<p> + + <li>Avoid use of floating point types (<code>float</code> and + <code>double</code>) and operations + unless absolutely necessary. Not all ACE platforms support them. + Therefore, wherever they are used, <code>ACE_LACKS_FLOATING_POINT</code> + conditional code must be also be used.<p> + + <li>Avoid including the string "<code>Error</code>" in a source + code filename. GNU Make's error messages start with + "<code>Error</code>". So, it's much easier to search for + errors if filenames don't contain "<code>Error</code>".<p> + + + <li>Narrow interfaces are better than wide interfaces. If there + isn't a need for an interface, leave it out. This eases maintenance, + minimizes footprint, and reduces the likelihood of interference + when other interfaces need to be added later. (See the + <a href="#ACE_Time_Value example">ACE_Time_Value</a> example + .<p> + + <li> Never use <CODE>assert()</CODE> macros or related constructs + (such as abort()) calls in core ACE, TAO, and CIAO + library/framework code. These macros are a major problem for + production software that uses this code since the + error-handling strategy (i.e., abort the process) is + excessive. Instead, extract out the expressions from + assert() macros and use them as + precondition/postconditions/invariants in the + software and return any violations of these + conditions/invariants via exceptions or error return values. + It's fine to use <CODE>assert()</CODE> macros et al. in test + programs, but make sure these tests never find their way into + the core ACE, TAO, and CIAO library/framework code base. <P> + + </ul> + + <li><strong>Code Documentation</strong><p> + <ul> + <li>Use comments and whitespace (:-) liberally. Comments + should consist of complete sentences, <em>i.e.</em>, start + with a capital letter and end with a period.<p> + + <li>Insert a CVS/RCS keyword string at the top of every source file, + Makefile, config file, <em>etc</em>. For C++ files, it is: + <pre> + // $<!-- -->Id$ + </pre> + It is not necessary to fill in the fields of the keyword string, + or modify them when you edit a file that already has one. CVS + does that automatically when you checkout or update the file.<p> + + To insert that string at the top of a file: + <pre> + perl -pi -e \ + 'if (! $o) {printf "// \$<!-- -->Id\$\n\n";}; $o = 1;' <em>file</em> + </pre><p> + + <li>Be sure to follow the guidelines and restrictions for use of the + documentation tools for ACE + header files, which must follow the + <a href="http://www.doxygen.org/">Doxygen</a> + format requirements. + The complete documentation for Doxygen is available in the + <a href="http://www.stack.nl/~dimitri/doxygen/download.html#latestman">Doxygen + manual</a>. + For an example header file using Doxygen-style comments, + please refer to <a href="../ace/ACE.h">ACE.h</a>.<p> + + <LI>All binary options for ACE and TAO should be specified in + terms of the integral values 0 and 1, rather than "true" and + "false" or "yes" and "no". All TAO options should be + documented in the <A HREF="../TAO/docs/Options.html">online + TAO options document</A>. <P>. + + </ul> + + <li><strong>Preprocessor</strong><p> + <ul> + <li>Never #include standard headers directly, except in a few + specific ACE files, <em>e.g.</em>, OS.h and stdcpp.h. Let + those files #include the correct headers. If you do not do + this, your code will not compile with the Standard C++ Library.<p> + + <li>Always follow a preprocessor <strong><code>#endif</code></strong> + with a <strong><code>/* */</code></strong> C-style comment. It + should correspond to the condition in the matching + <strong><code>#if</code></strong> directive. For example, + <pre> + #if defined (ACE_HAS_THREADS) + # if defined (ACE_HAS_STHREADS) + # include /**/ <synch.h> + # include /**/ <thread.h> + # define ACE_SCOPE_PROCESS P_PID + # define ACE_SCOPE_LWP P_LWPID + # define ACE_SCOPE_THREAD (ACE_SCOPE_LWP + 1) + # else + # define ACE_SCOPE_PROCESS 0 + # define ACE_SCOPE_LWP 1 + # define ACE_SCOPE_THREAD 2 + # endif /* ACE_HAS_STHREADS */ + #endif /* ACE_HAS_THREADS */ + </pre><p> + + <li>Be sure to put spaces around comment delimiters, e.g., + <strong><code>char * /* foo */</code></strong> instead of + <strong><code>char */*foo*/</code></strong>. MS VC++ + complains otherwise.<p> + + <li>Always insert a <strong><code>/**/</code></strong> between an + <strong><code>#include</code></strong> and + <strong><code>filename</code></strong>, for system headers and + <strong><code>ace/pre.h</code></strong> and + <strong><code>ace/post.h</code></strong> as + shown in the above example. This avoids dependency problems + with Visual C++ and prevents Doxygen from including the + headers in the file reference trees. <p> + + <li>Be very careful with names of macros, <code>enum</code> values, and variables + It's always best to prefix them with something like <code>ACE_</code> + or <code>TAO_</code>. There are too many system headers out + there that <code>#define</code> <code>OK</code>, <code>SUCCESS</code>, + <code>ERROR</code>, <code>index</code>, <code>s_type</code>, + and so on.<p> + + <li>When using macros in an arithmetic expression, be sure to test + that the macro is defined, using <code>defined(<em>macro</em>)</code> before specifying + the expression. For example: +<pre> +#if __FreeBSD__ < 3 +</pre> + +will evaluate true on any platform where <code>__FreeBSD__</code> is +not defined. The correct way to write that guard is: +<pre> +#if defined (__FreeBSD__) && __FreeBSD__ < 3 +</pre> + +If using g++, problems like this can be flagged as a warning by using the "<code>-Wundef</code>" command line option. + + <li>Try to centralize <code>#ifdef</code>s with <code>typedef</code>s + and <code>#define</code>s. For example, use this: + <pre> + #if defined(ACE_PSOS) + typedef long ACE_NETIF_TYPE; + # define ACE_DEFAULT_NETIF 0 + #else /* ! ACE_PSOS */ + typedef const TCHAR* ACE_NETIF_TYPE; + # define ACE_DEFAULT_NETIF ASYS_TEXT("le0") + #endif /* ! ACE_PSOS */ + </pre><p> + + instead of: + + <pre><p> + #if defined (ACE_PSOS) + // pSOS supports numbers, not names for network interfaces + long net_if, + #else /* ! ACE_PSOS */ + const TCHAR *net_if, + #endif /* ! ACE_PSOS */ + </pre><p> + + <li>Protect header files against multiple inclusion with this + construct: + <pre> + #ifndef FOO_H + #define FOO_H + + [contents of header file] + + #endif /* FOO_H */ + </pre><p> + + This exact construct (note the <code>#ifndef</code>) + is optimized by many compilers such they only open the + file once per compilation unit. Thanks to Eric C. Newton + <ecn@smart.net> for pointing that out.<p> + + If the header <code>#include</code>s an ACE library header, + then it's a good idea to include the <code>#pragma once</code> + directive: + <pre> + #ifndef FOO_H + #define FOO_H + + #include "ace/ACE.h" + #if !defined (ACE_LACKS_PRAGMA_ONCE) + # pragma once + #endif /* ACE_LACKS_PRAGMA_ONCE */ + + [contents of header file] + + #endif /* FOO_H */ + </pre><p> + + <code>#pragma once</code> must be protected, because some + compilers complain about it. The protection depends on + <code>ACE_LACKS_PRAGMA_ONCE</code>, which is defined in + some ACE config headers. Therefore, the protected + <code>#pragma once</code> construct should only be used after + an <code>#include</code> of an ACE library header. Note that + many compilers enable the optimization if the <code>#ifndef</code> + protection construct is used, so for them, <code>#pragma once</code> + is superfluous.<p> + + <strong>No</strong> code can appear after the final + <code>#endif</code> for the optimization to be effective and + correct.<p> + + <li><p>Files that contain parametric classes should follow this style: + <pre> + #ifndef FOO_T_H + #define FOO_T_H + + #include "ace/ACE.h" + #if !defined (ACE_LACKS_PRAGMA_ONCE) + # pragma once + #endif /* ACE_LACKS_PRAGMA_ONCE */ + + // Put your template declarations here... + + #if defined (__ACE_INLINE__) + #include "Foo_T.inl" + #endif /* __ACE_INLINE__ */ + + #if defined (ACE_TEMPLATES_REQUIRE_SOURCE) + #include "Foo_T.cpp" + #endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + + #if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) + #pragma implementation "Foo_T.cpp" + #endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + + #endif /* FOO_T_H */ +</pre></p> + <p> + Notice that some compilers need to see the code of the template, + hence the <code>.cpp</code> file must be included from the + header file. + </p> + <p> + To avoid multiple inclusions of the <code>.cpp</code> file it + should also be protected as in: + <pre> + #ifndef FOO_T_CPP + #define FOO_T_CPP + + #include "Foo_T.h" + #if !defined (ACE_LACKS_PRAGMA_ONCE) + # pragma once + #endif /* ACE_LACKS_PRAGMA_ONCE */ + + #if !defined (__ACE_INLINE__) + #include "ace/Foo_T.inl" + #endif /* __ACE_INLINE__ */ + + // put your template code here + + #endif /* FOO_T_H */ +</pre></p> + <p>Finally, you may want to include the template header file from a + non-template header file (check + <code>$ACE_ROOT/ace/Synch.h</code>); in such a case the template + header should be included <strong>after</strong> the inline + function definitions, as in:</p> + <p><pre> + #ifndef FOO_H + #define FOO_H + + #include "ace/ACE.h" + #if !defined (ACE_LACKS_PRAGMA_ONCE) + # pragma once + #endif /* ACE_LACKS_PRAGMA_ONCE */ + + // Put your non-template declarations here... + + #if defined (__ACE_INLINE__) + #include "Foo.inl" + #endif /* __ACE_INLINE__ */ + + #include "Foo_T.h" + + #endif /* FOO_H */ +</pre></p></li> + + <li>Avoid <code>#include <math.h></code> if at all possible. + The <code>/usr/include/math.h</code> on SunOS 5.5.1 through 5.7 + defines a struct name <strong>exception</strong>, which complicates + use of exceptions.<p> + + <li>On a <code>.cpp</code> file always include the corresponding + header file <em>first</em>, like this:<p> +<pre> + // This is Foo.cpp + + #include "Foo.h" + #include "tao/Bar.h" + #include "ace/Baz.h" + + // Here comes the Foo.cpp code.... +</pre><p> + + In this way we are sure that the header file is self-contained + and can be safely included from some place else. + + <li>In the TAO library <strong>never</strong> include + <code><corba.h></code>, this file should only be included + by the user and introduces cyclic dependencies in the library + that we must avoid.<p> + + <li>Never include a header file when a forward reference will do, + remember that templates can be forward referenced too. + Consult your favorite C++ book to find out when you must include + the full class definition.<p> + </ul> + + <li><strong>C++ Syntax and Constructs</strong><p> + <ul> + <li><strong><code>for</code></strong> loops should look like: + <pre> + for (unsigned int i = 0; i < count; ++i) + ++total; + </pre> + Though, I prefer to always wrap the body of the loop in braces, + to avoid surprises when other code or debugging statements are + added, and to maintain sanity when the body consists of a macro, + such as an <code>ACE_ASSERT</code> without a trailing semicolon: + <pre> + for (unsigned int i = 0; i < count; ++i) + { + ACE_ASSERT (++total < UINT_MAX;) + } + </pre><p> + + Similarly, <strong><code>if</code></strong> statements should have + a space after the "<strong>if</strong>", and no spaces just after + the opening parenthesis and just before the closing parenthesis.<p> + + <li>If a loop index is used after the body of the loop, it + <strong>must</strong> be declared before the loop. For example, + + <pre> + size_t i = 0; + for (size_t j = 0; file_name [j] != '\0'; ++i, ++j) + { + if (file_name [j] == '\\' && file_name [j + 1] == '\\') + ++j; + + file_name [i] = file_name [j]; + } + + // Terminate this string. + file_name [i] = '\0'; + </pre><p> + + <li>Prefix operators are generally more efficient than postfix + operators. Therefore, they are preferred over their postfix + counterparts where the expression value is not used.<p> + + Therefore, use this idiom for iterators, with prefix operator + on the loop index: + <pre> + ACE_Ordered_MultiSet<int> set; + ACE_Ordered_MultiSet_Iterator<int> iter(set); + + for (i = -10; i < 10; ++i) + set.insert (2 * i + 1); + + </pre> + rather than the postfix operator: + <pre> + for (i = -10; i < 10; i++) + set.insert (2 * i + 1); + </pre><p> + + <li>Prefer using <strong> <code> if (...) else .... </code> </strong> + instead of <strong> <code> ?: </code> </strong> operator. It is a lot + less error prone, and will help you avoid bugs caused due to the + precedence of <strong> <code> ?: </code> </strong>, compared with other + operators in an expression. + + <li>When a class provides <code>operator==</code>, it must also provide + <code>operator!=</code>. Also, both these operators must be + <code>const</code> and return <code>bool</code>. + + <li>Avoid unnecessary parenthesis. We're not writing Lisp :-)<p> + + <li>Put inline member functions in a <strong><code>.inl</code></strong> + file. That file is conditionally included by both the + <strong><code>.h</code></strong> file, for example:<p> + + <pre> + class ACE_Export ACE_High_Res_Timer + { + [...] + }; + + #if defined (__ACE_INLINE__) + #include "ace/High_Res_Timer.inl" + #endif /* __ACE_INLINE__ */ + </pre><p> + + and <strong><code>.cpp</code></strong> file:<p> + + <pre> + #define ACE_BUILD_DLL + #include "ace/High_Res_Timer.h" + + #if !defined (__ACE_INLINE__) + #include "ace/High_Res_Timer.inl" + #endif /* __ACE_INLINE__ */ + + ACE_ALLOC_HOOK_DEFINE(ACE_High_Res_Timer) + </pre><p> + + <strong>NOTE:</strong> It is very important to ensure than an + inline function will not be used before its definition is seen. + Therefore, the inline functions in the .inl file should be arranged + properly. Some compilers, such as <code>g++</code> with the + <code>-Wall</code> option, will issue warnings for violations.<p> + + <li>Some inlining heuristics:<p> + <ul> + <li>One liners should almost always be inline, as in: +<pre> +ACE_INLINE +Foo::bar () +{ + this->baz (); +} +</pre><p> + + <li>The notable exception is virtual functions, which should + generally not be inlined.<p> + + <li>Big (more than 10 lines) and complex function (more than one if () + statement, or a switch, or a loop) should not be inlined.<p> + + <li>Medium sized stuff depends on how performance critical it is. + If you know that it's in the critical path, then make it + inline. When in doubt, profile the code.<p> + </ul> + + <li><code>ACE_Export</code> must be inserted between the + <code>class</code> keyword and class name for all classes that + are exported from libraries, as shown in the example above. + <strong>However</strong>, do <strong>not</strong> use + <code>ACE_Export</code> for template classes or classes that + are not used out of the ACE library, for example.!<p> + + <li>Mutators and accessors should be of this form:<p> + + <pre> + void object_addr (const ACE_INET_Addr &); + // Sets <object_addr_> cache from <host> and <port>. + + const ACE_INET_Addr &object_addr const (void); + // Returns the <ACE_INET_Addr> for this profile. + </pre><p> + + instead of the "set_" and "get_" form.<p> + + <li>Never use <strong><code>delete</code></strong> to deallocate + memory that was allocated with <strong><code>malloc</code></strong>. + Similarly, never associate <strong><code>free</code></strong> with + <strong><code>new</code></strong>. + <strong><code>ACE_NEW</code></strong> or + <strong><code>ACE_NEW_RETURN</code></strong> should be used to + allocate memory, and <strong><code>delete</code></strong> should + be used to deallocate it. And be careful to use the correct form, + <strong><code>delete</code></strong> or + <strong><code>delete []</code></strong> to correspond to the + allocation.<p> + + <li>Don't check for a pointer being 0 before deleting it. It's + always safe to delete a 0 pointer. If the pointer is visible + outside the local scope, it's often a good idea to 0 it + _after_ deleting it. Note, the same argument applies to + free().<p> + + <li>Always use <strong><code>ACE_NEW</code></strong> or + <strong><code>ACE_NEW_RETURN</code></strong> to allocate memory, + because they check for successful allocation and set errno + appropriately if it fails.<p> + + <li>Never compare or assign a pointer value with <strong>NULL</strong>; + use <strong>0</strong> instead. The language allows any pointer to + be compared or assigned with <strong>0</strong>. The definition + of <strong>NULL</strong> is implementation dependent, so it is + difficult to use portably without casting.<p> + + <li>Never cast a pointer to or from an <strong><code>int</code></strong>. + On all currently supported ACE platforms, it is safe to cast + a pointer to or from a <strong><code>long</code></strong>.<p> + + <li>Be very careful when selecting an integer type that must be a + certain size, <em>e.g.</em>, 4 bytes. <strong>long</strong> is + not 4 bytes on all platforms; it is 8 bytes on many 64-bit + machines. ACE_UINT32 is always 4 bytes, and ACE_UINT64 is + always 8 bytes.<p> + + <li>If a class has any virtual functions, and its destructor is + declared explicitly in the class, then the destructor should + <strong>always</strong> be virtual as well. And to support + compiler activities such as generation of virtual tables and, + in some cases, template instantiation, the virtual destructor + should <strong>not be inline</strong>. (Actually, any non-pure + virtual function could be made non-inline for this purpose. But, + for convenience, if its performance is not critical, it is usually + easiest just to make the virtual destructor non-inline.)<p> + + + <li><a name="ACE_Time_Value example">Avoid default arguments</a> + unless there's a good reason. For an example of how they got + us into a jam is: + <pre> + ACE_Time_Value (long sec, long usec = 0); + </pre> + + So, <code>ACE_Time_Value (2.5)</code> has the unfortunate + effect of coercing the 2.5 to a long with value 2. That's + probably not what the programmer intended, and many compilers + don't warn about it.<p> + + A nice fix would be to add an <code>ACE_Time_Value (double)</code> + constructor. But, that would cause ambiguous overloading + due to the default value for the second argument of + <code>ACE_Time_Value (long sec, long usec = 0)</code>. + We're stuck with <code>ACE_Time_Value</code>, but now we + know that it's easy to avoid.<p> + + <li>Constructor initializers must appear in the same order as + the data members are declared in the class header. This avoids + subtle errors, because initialization takes place in the order + of member declaration.<p> + + <li>Initialization is usually cleaner than assignment, especially + in a conditional. So, instead of writing code like this: + + <pre> + ssize_t n_bytes; + + // Send multicast of one byte, enough to wake up server. + if ((n_bytes = multicast.send ((char *) &reply_port, + sizeof reply_port)) == -1) + </pre> + + Write it like this: + + <pre> + ssize_t n_bytes = multicast.send ((char *) &reply_port, + sizeof reply_port) + + // Send multicast of one byte, enough to wake up server. + if (n_bytes == -1) + </pre><p> + + But, beware if the initialization is of a static variable. + A static variable is only initialized the first time its + declaration is seen. Of course, we should avoid using + static (and non-constant) variables at all.<p> + + <li>It is usually clearer to write conditionals that have + both branches without a negated condition. For example,<p> + + <pre> + if (test) + { + // true branch + } + else + { + // false branch + } + </pre><p> + + is preferred over:<p> + + <pre> + if (! test) + { + // false test branch + } + else + { + // true test branch + } + </pre><p> + + <li>If a cast is necessary, avoid use of C-style "sledgehammer" + casts. Use standard C++ casts + (e.g. <code>static_cast<int> (foo)</code>) instead.<p> + + <li>In general, if instances of a class should not be copied, + then a private copy constructor and assignment operator should + be declared for the class, but not implemented. For example: + + <pre> + // Disallow copying by not implementing the following . . . + ACE_Object_Manager (const ACE_Object_Manager &); + ACE_Object_Manager &operator= (const ACE_Object_Manager &); + </pre><p> + + If the class is a template class, then the + <code>ACE_UNIMPLEMENTED_FUNC</code> macro should be used: + + <pre> + // = Disallow copying... + ACE_UNIMPLEMENTED_FUNC (ACE_TSS (const ACE_TSS<TYPE> &)) + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_TSS<TYPE> &)) + </pre><p> + + <code>ACE_UNIMPLEMENTED_FUNC</code> can be used with non-template + classes as well. Though for consistency and maximum safety, it + should be avoided for non-template classes.<p> + + <li>Never use <code>BOOL</code>, or similar types. + (<code>ACE_CDR::Boolean</code> and + <code>CORBA::Boolean</code> are acceptable). Use the + standard C++ <code>bool</code> for boolean variables, instead.<p> + + <li>Functions should always return -1 to indicate failure, and + 0 or greater to indicate success.<p> + + <li>Separate the code of your templates from the code for + non-parametric classes: some compilers get confused when + template and non-template code is mixed in the same file.<p> + + <li>It's a good idea to specify the include path (with <code>-I</code>) + to include any directory which contains files with template + definitions. The Compaq Tru64 cxx <code>-ptv</code> compiler option + may help diagnose missing template instantiation problems.<p> + + <li>When referring to member variables and functions, use + <code>this-></code><em>member</em>. This makes it clear to the + reader that a class member is being used. It also makes it crystal + clear to the compiler which variable/function you mean in cases + where it might make a difference. <p> + + <li>Don't use template template arguments, this C++ construct is not + supported by the HP aCC 3.70 compiler at this moment. For example the + following template decleration is one that just doesn't work. + <pre> + template<typename S_var, size_t BOUND, template <typename> class Insert_Policy> class A {}; + </pre> + + <li><strong>I/O</strong><p> + <ul> + <li>Use <strong><code>ACE_DEBUG</code></strong> for printouts, + and <strong><code>ACE_OS::fprintf ()</code></strong> for + file I/O. Avoid using iostreams because of implementation + differences across platforms.<p> + <li>After attempting to open an existing file, always check for success. + Take appropriate action if the open failed.<p> + <li>Notice that <strong><code>ACE_DEBUG</code></strong> and + <strong><code>ACE_ERROR</code></strong> don't support + <code>%ld</code> of any other multicharacter format.<p> + </ul> + + <li><strong>WCHAR conformity</strong><p> + + <ul> + <li>For ACE, use <code>ACE_TCHAR</code> instead of char for strings and <code>ACE_TEXT()</code> + around string literals. Exceptions are <code>char</code> + arrays used for data and strings that need to remain as 1 + byte characters. + + <li>If you have a char string that needs to be converted to <code>ACE_TCHAR</code>, + use the <code>ACE_TEXT_CHAR_TO_TCHAR()</code> macro. If you have a <code>ACE_TCHAR</code> + string that needs to be converted to a <code>char</code> string, use the + <code>ACE_TEXT_ALWAYS_CHAR()</code> macro + + <li>Do not use the Win32 <code>TCHAR</code> macros. The wide character-ness of ACE + is separate from UNICODE and _UNICODE. + + <li>For TAO, don't use <code>ACE_TCHAR</code> or <code>ACE_TEXT</code>. The CORBA specification + defines APIs as using char. So most of the time there is no need + to use wide characters. + </ul><P> + + <li><strong>Exceptions</strong><p> + + <ul> + <li>There are many ways of throwing and catching exceptions. The + code below gives several examples. Note that each method has + different semantics and costs. Whenever possible, use the + first approach.<p> + + <pre> + #include "iostream.h" + + class exe_foo + { + public: + exe_foo (int data) : data_ (data) + { cerr << "constructor of exception called" << endl; } + ~exe_foo () + { cerr << "destructor of exception called" << endl; } + exe_foo (const exe_foo& foo) : data_ (foo.data_) + { cerr << "copy constructor of exception called" + << endl; } + int data_; + }; + + + void + good (int a) + { + throw exe_foo (a); + }; + + void + bad (int a) + { + exe_foo foo (a); + throw foo; + }; + + int main () + { + cout << endl << "First exception" << endl + << endl; + try + { + good (0); + } + catch (exe_foo &foo) + { + cerr << "exception caught: " << foo.data_ + << endl; + } + + cout << endl << "Second exception" << endl + << endl; + try + { + good (0); + } + catch (exe_foo foo) + { + cerr << "exception caught: " << foo.data_ + << endl; + } + + cout << endl << "Third exception" << endl + << endl; + try + { + bad (1); + } + catch (exe_foo &foo) + { + cerr << "exception caught: " << foo.data_ + << endl; + } + + cout << endl << "Fourth exception" << endl + << endl; + try + { + bad (1); + } + catch (exe_foo foo) + { + cerr << "exception caught: " << foo.data_ + << endl; + } + + return 0; + } + </pre> + + Output is: <p> + + <pre> + First exception + + constructor of exception called + exception caught: 0 + destructor of exception called + + Second exception + + constructor of exception called + copy constructor of exception called + exception caught: 0 + destructor of exception called + destructor of exception called + + Third exception + + constructor of exception called + copy constructor of exception called + destructor of exception called + exception caught: 1 + destructor of exception called + + Fourth exception + + constructor of exception called + copy constructor of exception called + destructor of exception called + copy constructor of exception called + exception caught: 1 + destructor of exception called + destructor of exception called + + </pre> + + </ul><p> + + <li><strong>Compilation</strong><p> + <ul> + <li>Whenever you add a new test or example to ACE or TAO, make + sure that you modify the MPC file in the parent directory. + This will make sure that your code gets compiled on a + regular basis.<p> + </ul><p> +</ul> + +<hr> +<h3><a href="http://www.cs.wustl.edu/~schmidt/ACE-overview.html">ACE</a> + Shared Libary Guidelines</h3> + <ul> + <li> + <p> + Create a separate export macro for each dynamic library. A + header file containing the export macro and additional + support macros should be generated by using the <a + href="../bin/generate_export_file.pl">ACE_wrappers/bin/generate_export_file.pl</a> Perl script. + </p> + </li> + <li> + <p> + Make sure that your classes, structures and free functions + are annotated with this export macro. The only exceptions + are pure template classes, structures and free functions. + </p> + <p> + Only classes (and structures, free functions, etc) that are + part of the library public interface must be exported + (e.g. declared with an export macro). Those that are only + meant to be used internally need not be exported, + particularly for g++ <code>>=</code>4.0 since doing so + defeats some neat optimizations. Here's a common case in + where an export macro is generally used unnecessarily: + </p> + <blockquote> + <pre> +class FooExport Foo +{ +public: + virtual void kung_fu () = 0; +}; + +class FooExport Bar : public Foo +{ +public: + virtual void kung_fu () { ... } +}; + +class FooExport FooFactory +{ +public: + Foo * make_foo () + { + // Assume that this implementation is hidden from + // the application and is consequently out of line. + return new Bar(); + } +}; + </pre> + </blockquote> + <p> + Here the application is only meant to invoke operations + through a pointer or reference to the abstract base class + "<code>Foo</code>" created by the "<code>FooFactory</code>", + not the "<code>Bar</code>" subclass. In this case, + exporting "<code>Bar</code>" is unnecessary. If your + concrete class is meant to be used outside of the shared + library (e.g. as a template parameter, within a + <code>dynamic_cast<></code>, etc) you must then export + it. Otherwise, avoid doing so if you can. + </p> + </li> + <li> + <p> + Make sure that you specify that you are creating a dynamic + library in your <a href="../MPC/README">MPC</a> file by adding + a <code>sharedname</code> tag. + </p> + </li> + <li> + <p> + Make sure that you add the <code>FOO_BUILD_DLL</code> + preprocessor symbol to the <code>dynamicflags</code> of the + MPC project that is used to build a library. Note that the + export files are setup such that when this macro is defined, + the symbols are exported, otherwise they are imported. The + default behaviour is to set up for import so that clients of + your library don't need to worry about arcane build flags + like <code>FOO_BUILD_DLL</code> in their build setup. This + ties back to the first item. + </p> + </li> + <li> + <p> + When you specify the order of libraries to link to, make + sure that the dependent libraries come after the libraries + which depend on them, i.e., your link line should always + contain <code>-lDependsOnFoo -lFoo</code>. Note that this + is not a requirement on GNU/Linux but linkers on other + platforms are not as forgiving. + </p> + </li> + <li> + <p> + Use the <code>ACE_SINGLETON_DECLARE</code> macro to declare + a class as a singleton. Declare exported (i.e. default + visibility) singleton templates prior to typedefs that + reference them. This prevents g++ 4.0 from silently making + their visibility hidden (see <a + href="http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=2260">Bug 2260</a> for details). + </p> + </li> + <li> + <p> + Avoid inlining virtual functions in classes that must be + exported since doing so can cause RTTI related problems + (e.g. <code>dynamic_cast<> failures</code>) when using + g++ >= 4.0 due to our use of that compiler's "visibility + attribute" support that is tied in to the export macros. + This includes virtual destructors automatically created by + the compiler when you don't declare one. Make sure you + define a no-op out-of-line virtual destructor if your base + class has a virtual destructor since you may otherwise run + into the mentioned RTTI problems. + </p> + </li> + </ul> + + +<hr> +<h3><a href="http://www.cs.wustl.edu/~schmidt/ACE-overview.html">ACE</a> + Usage Guidelines</h3> +<ul> + <li>Always use the <strong><code>ACE_OS</code></strong> + namespace functions instead of bare OS system calls.<p> + + <li>As a general rule, the only functions that should go into the + <strong><code>ACE_OS</code></strong> namespace are ones that + have direct equivalents on some OS platform. Functions that + are extensions should go in the + <strong><code>ACE</code></strong> namespace.<p> + + <li>Use the <strong><code>ACE_SYNCH_MUTEX</code></strong> macro, + instead of using one of the specific mutexes, such as + <strong><code>ACE_Thread_Mutex</code></strong>. This provides + portability between threaded and non-threaded platforms.<p> + + <li>Avoid creating a static instance of user-defined (class) type. + Instead, either create it as an + <strong><code>ACE_Singleton</code></strong>, + <strong><code>ACE_TSS_Singleton</code></strong>, or as an + <strong><code>ACE_Cleanup</code></strong> object. See the + <strong>ACE</strong> + <a href="../ace/Singleton.h"><code>Singleton.h</code></a>, + <a href="../ace/Object_Manager.h"><code>Object_Manager.h</code></a>, and + <a href="../ace/Managed_Object.h"><code>Managed_Object.h</code></a> + header files for more information.<p> + + Static instances of built-in types, such as + <strong><code>int</code></strong> or any pointer type, are fine.<p> + + Construction of static instance of a user-defined type should + <em>never</em> spawn threads. Because order of construction of + statics across files is not defined by the language, it is usually + assumed that only one thread exists during static construction. + This allows statics suchs as locks to be safely created. We do not + want to violate this assumption.<p> + + <li>Do not use C++ exception handling directly. Some platforms do + not support it. And, it can impose an execution speed penalty. + Instead use the TAO/ACE try/catch macros.<p> + + <li>Because ACE does not use exception handling, dealing with + failures requires a bit of care. This is especially true + in constructors. Consider the following approach: + + <pre> + ACE_NEW_RETURN (this->name_space_, LOCAL_NAME_SPACE, -1); + + if (ACE_LOG_MSG->op_status () != 0) + .... + </pre> + + This snip of code is from + <a href="../ace/Naming_Context.cpp"><code>ACE_Naming_Context</code></a>. + All failed constructors in ACE (should) call ACE_ERROR. This sets + the thread-specific <strong>op_status</strong>, which can be checked + by the caller. This mechanism allows the caller to check for a failed + constructor without the requiring the constructor to throw + exceptions.<p> + + <LI>Another consequence of ACE's avoidance of exception handling is + that you should use <CODE>open()</CODE> methods on classes that + perform initializations that can fail. This is because <CODE>open()</CODE> + returns an error code that's easily checked by the caller, + rather than relying on constructor and thread-specific status + values. <P> + + <li>Avoid using the C++ Standard Template Library (STL) in our + applications. Some platforms do not support it yet. It is + safe to use the STL generic algoritms. The following have been + used already and don't seem to cause any portability issues: + <pre> + std::swap + std::for_each + std::fill + std::generate + std::transform + std::copy + </pre><p> + + <li>Be <em>very</em> careful with <code>ACE_ASSERT</code>. It + must only be used to check values; it may never be used to + wrap a function call, or contain any other side effect. That's + because the statement will disappear when ACE_NDEBUG is enabled. + For example, this code is BAD: + <pre> + ACE_ASSERT (this->next (retv) != 0); // BAD CODE! + </pre> + + Instead, the above should be coded this way: + + <pre> + int const result = this->next (retv); + ACE_ASSERT (result != 0); + ACE_UNUSED_ARG (result); + </pre><p> + + <li>Never put side effects in <code>ACE_DEBUG</code> code: + <pre> + ACE_DEBUG ((LM_DEBUG, + "handling signal: %d iterations left\n", + --this->iterations_)); // BAD CODE! + </pre> + + Note that this won't work correctly if <code>ACE_NDEBUG</code> is + defined, for the same reason that having side-effects in + <code>ACE_ASSERT</code>s won't work either, <em>i.e.</em>, because + the code is removed.<p> + + <li>Be <strong>very</strong> careful with the code that you put + in a signal handler. On Solaris, the man pages document systems + calls as being Async-Signal-Safe if they can be called from signal + handlers. In general, it's best to just set a flag in a signal + handler and take appropriate action elsewhere. It's also best + to avoid using signals, especially asynchronous signals.<p> + + <li>Immediately after opening a temporary file, unlink it. For + example: + <pre><code> + ACE_HANDLE h = open the file (filename); + + ACE_OS::unlink (filename); + </code></pre><p> + + This avoids leaving the temporary file even if the program crashes.<p> + + <li>Be sure to specify the <code>THR_BOUND</code> thread creation + flag for time-critical threads. This ensures that the thread competes + for resources globally on Solaris. It is harmless on other platforms.<p> +</ul> + + +<hr> +<h3><a href="http://www.cs.wustl.edu/~schmidt/ACE-overview.html">Other + ACE</a> and + <a href="http://www.cs.wustl.edu/~schmidt/TAO-overview.html">TAO</a> + Guidelines</h3> +<ul> + <li>When enhancing, updating, or fixing ACE or TAO, always:<p> + <ol> + <li>Test your change on at least one platform. All changes + <strong>must</strong> be tested with egcs before commiting. + That means you may need to test on at least two platforms.<p> + <li>An an entry to the appropriate ChangeLog. TAO and some + ACE subdirectories, such as <a href="../ASNMP">ASNMP</a>, + <a href="../apps/JAWS">JAWS</a>, and + <a href="../apps/gperf">gperf,</a> have their + own ChangeLogs. If you don't use one of those, use the + <a href="../ChangeLog">ChangeLog</a> in the top-level + <a href="..">ACE_wrappers</a> directory.<p> + <li>Commit your change using a message of this form:<p> +<code> +ChangeLogTag: Thu Jul 22 09:55:10 UTC 1999 David L. Levine + <levine@cs.wustl.edu> +</code><p> + <li>If the change is in response to a request by someone else: + <ol> + <li>Make sure that person is acknowledged in + <a href="../THANKS">ACE_wrappers/THANKS</a>, and<p> + <li>Respond to that person.<p> + </ol> + </ol> + + <li>Never add copyrighted, confidential, or otherwise restricted + code to the ACE or TAO distributions without written permission + from the owner.<p> +</ul> + + +<hr> +<h3><a href="http://www.cs.wustl.edu/~levine/CVS.html">CVS</a> + Usage Guidelines</h3> +<ul> + <li>Always make sure that a change builds and executes correctly + on at least one platform before checking it into the CVS repository. + All changes <strong>must</strong> be tested with g++ before commiting. + That means you may need to test on at least two platforms.<p> +</ul> + + +<hr> +<h3>Script Guidelines</h3> +<ul> + <li>In general, it's best to write scripts in Perl. It's + OK to use Bourne shell. Never, never, never use csh, ksh, + bash, or any other kind of shell.<p> + + <li>Follow the Perl style guide guide as closely as + possible. <code>man perlstyle</code> to view it. + + <li>Don't specify a hard-coded path to Perl itself. Use + the following code at the top of the script to pick up + perl from the users <code>PATH</code>:<br> + <pre> +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + </pre><p> + + <li>Never, never, never start the first line of a script + with "<code>#</code>", unless the first line is "<code>#! /bin/sh</code>". + With just "<code>#</code>", t/csh users will spawn a new shell. + That will cause their <code>.[t]cshrc</code> to be + processed, possibly clobbering a necessary part of + their environment.<p> + + <li>If your Perl script relies on features only available + in newer versions of Perl, include the a statement similar + to the following:<br> + <pre> + require 5.003; + </pre> + + <li>Don't depend on <strong><code>.</code></strong> being + in the user's path. If the script spawns another executable + that is supposed to be in the current directory, be sure the + prefix its filename with <strong><code>.</code></strong>.<p> +</ul> + + +<hr> +<h3>Software Engineering Guidelines</h3> +<ul> + <li><strong>Advise</strong>: Keep other developers informed of problems + and progress.<p> + + <li><strong>Authorize</strong>: We have contractual obligations to not + unilaterally change interfaces. If you need to change or remove an + interface, get an OK.<p> + + <li><strong>Minimize</strong> risk: Test all changes. Solicit review of + changes.<p> + + <li><strong>Revise</strong> only when necessary: Every change has risk, + so avoid making any change unless there is a good reason for it.<p> + + <li><strong>Normalize</strong>: Factor out commonality. For example, + maintain a data value in only one place.<p> + + <li><strong>Synthesize</strong>: Build stubs and scaffolding early to + simulate the complete system. Maintain a checked-in version of the + system that cleanly builds and tests at all times.<p> + + <li><strong>Be available</strong>: Breaking compilation in one + platform or another should be avoided (see above), + but it is bound to happen when so many platforms are in use. + Be available after making a change, + if you won't be available for at least 48 hours after the change + is made then don't make it!<p> +</ul> + + + +<hr> +<h3><a href="http://www.cs.wustl.edu/~schmidt/rules.html">ACE + Design Rules</a></h3> + + +<hr><p> + <font size=-1> +<!-- hhmts start --> +Last modified: Wed Nov 23 11:00:44 CST 2005 +<!-- hhmts end --> + </font><p> + + + +Back to <A HREF="index.html">ACE Documentation Home</A>. + +</body> +</html> |