(setq-default indent-tabs-mode nil)Microsoft Visual C++ users should do the following:
Choose: Tools -- Options -- Tabs Then Set: "Tab size" to 8 and "Indent size" to 2, and indent using spaces.
(setq-default nuke-trailing-whitespace-p t)Note for Microsoft Visual Studio .NET Users:
There is a macro project (ace_guidelines.vsmacros)
located in $ACE_ROOT/docs
that replaces tabs with spaces
and removes trailing spaces each time you save a file.
MakeProjectCreator
,
tao_idl
do not also go beyond that limit. Some operating
systems cannot handle very long file names correctly.
-?
command line argument, are
provided to the program.
int ACE_TMAIN (int argc, ACE_TCHAR *argv[])This form is portable to all ACE platforms whether using narrow or wide characters. The other two common forms:
int main (int argc, char *argv[]) int wmain (int argc, wchar_t *argv[])as well as any other main entrypoint form should only be used when there is some overarching reason to not use the portable form. One example would be a Windows GUI program that requires WinMain.
See $ACE_ROOT/docs/wchar.txt
for more information on ACE support on wchar
.
int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) { [...] return 0; }
If you don't use the argc
and/or argv
arguments, don't declare them, e.g.,
int ACE_TMAIN (int, ACE_TCHAR *[]) { [...] return 0; }
Please declare the second argument as ACE_TCHAR *[]
instead of ACE_TCHAR **
or char *[]
.
Ancient versions of MSC++
complained about ACE_TCHAR **
and char
*[]
is not Unicode-compliant.
main
must also return 0 on successful
termination, and non-zero otherwise.
float
and
double
) and operations
unless absolutely necessary. Not all ACE platforms support them.
Therefore, wherever they are used, ACE_LACKS_FLOATING_POINT
conditional code must be also be used.
Error
" in a source
code filename. GNU Make's error messages start with
"Error
". So, it's much easier to search for
errors if filenames don't contain "Error
".
assert()
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 assert()
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.
// $Id$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. SVN does that automatically when you checkout or update the file.
To insert that string at the top of a file:
perl -pi -e \ 'if (! $o) {printf "// \$Id\$\n\n";}; $o = 1;' file
.
#if defined (MACRONAME)
to test if a macro is defined, rather than the simpler
#if MACRONAME
. Doxygen requires this.
The one exception to this the macros used to prevent multiple
inclusion of header files, as shown below.
#endif
with a /* */
C-style comment. Using
C-style comments with preprocessor code is required for some old
compilers. It should correspond to the condition in the matching
#if
directive. For example,
#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 */
char * /* foo */
instead of
char */*foo*/
. MS VC++
complains otherwise.
/**/
between an
#include
and
filename
, for system headers and
ace/pre.h
and
ace/post.h
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.
enum
values, and variables
It's always best to prefix them with something like ACE_
or TAO_
. There are too many system headers out
there that #define
OK
, SUCCESS
,
ERROR
, index
, s_type
,
and so on.
defined(macro)
before specifying
the expression. For example:
#if __FreeBSD__ < 3will evaluate true on any platform where
__FreeBSD__
is
not defined. The correct way to write that guard is:
#if defined (__FreeBSD__) && __FreeBSD__ < 3If using g++, problems like this can be flagged as a warning by using the "
-Wundef
" command line option.
#ifdef
s with typedef
s
and #define
s. For example, use this:
#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 */
instead of:
#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 */
#ifndef FOO_H #define FOO_H [contents of header file] #endif /* FOO_H */
This exact construct (note the #ifndef
)
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.
If the header #include
s an ACE library header,
then it's a good idea to include the #pragma once
directive:
#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 */
#pragma once
must be protected, because some
compilers complain about it. The protection depends on
ACE_LACKS_PRAGMA_ONCE
, which is defined in
some ACE config headers. Therefore, the protected
#pragma once
construct should only be used after
an #include
of an ACE library header. Note that
many compilers enable the optimization if the #ifndef
protection construct is used, so for them, #pragma once
is superfluous.
No code can appear after the final
#endif
for the optimization to be effective and
correct.
Files that contain parametric classes should follow this style:
#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 */
Notice that some compilers need to see the code of the template,
hence the .cpp
file must be included from the
header file.
To avoid multiple inclusions of the .cpp
file it
should also be protected as in:
#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 */
Finally, you may want to include the template header file from a
non-template header file (check
$ACE_ROOT/ace/Synch.h
); in such a case the template
header should be included after the inline
function definitions, as in:
#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 */
#include <math.h>
if at all possible.
The /usr/include/math.h
on SunOS 5.5.1 through 5.7
defines a struct name exception, which complicates
use of exceptions.
.cpp
file always include the corresponding
header file first, like this:
// This is Foo.cpp #include "Foo.h" #include "tao/Bar.h" #include "ace/Baz.h" // Here comes the Foo.cpp code....
In this way we are sure that the header file is self-contained and can be safely included from some place else.
<corba.h>
, this file should only be included
by the user and introduces cyclic dependencies in the library
that we must avoid.
for
loops should look like:
for (unsigned int i = 0; i < count; ++i) ++total;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
ACE_ASSERT
without a trailing semicolon:
for (unsigned int i = 0; i < count; ++i) { ACE_ASSERT (++total < UINT_MAX;) }
Similarly, if
statements should have
a space after the "if", and no spaces just after
the opening parenthesis and just before the closing parenthesis.
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';
Therefore, use this idiom for iterators, with prefix operator on the loop index:
ACE_Ordered_MultiSet<int> set; ACE_Ordered_MultiSet_Iterator<int> iter(set); for (i = -10; i < 10; ++i) set.insert (2 * i + 1);rather than the postfix operator:
for (i = -10; i < 10; i++) set.insert (2 * i + 1);
if (...) else ....
instead of ?:
operator. It is a lot
less error prone, and will help you avoid bugs caused due to the
precedence of ?:
, compared with other
operators in an expression.
operator==
, it must also provide
operator!=
. Also, both these operators must be
const
and return bool
.
.inl
file. That file is conditionally included by both the
.h
file, for example:
class ACE_Export ACE_High_Res_Timer { [...] }; #if defined (__ACE_INLINE__) #include "ace/High_Res_Timer.inl" #endif /* __ACE_INLINE__ */
and .cpp
file:
#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)
NOTE: 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 g++
with the
-Wall
option, will issue warnings for violations.
ACE_INLINE Foo::bar () { this->baz (); }
ACE_Export
must be inserted between the
class
keyword and class name for all classes that
are exported from libraries, as shown in the example above.
However, do not use
ACE_Export
for template classes or classes that
are not used out of the ACE library, for example.!
/// Sets @c object_addr_ cache from @c host and @c port. void object_addr (const ACE_INET_Addr &); /// Returns the ACE_INET_Addr for this profile. const ACE_INET_Addr &object_addr const (void);
instead of the "set_" and "get_" form.
delete
to deallocate
memory that was allocated with malloc
.
Similarly, never associate free
with
new
.
ACE_NEW
or
ACE_NEW_RETURN
should be used to
allocate memory, and delete
should
be used to deallocate it. And be careful to use the correct form,
delete
or
delete []
to correspond to the
allocation.
ACE_NEW
or
ACE_NEW_RETURN
to allocate memory,
because they check for successful allocation and set errno
appropriately if it fails.
int
.
On all currently supported ACE platforms, it is safe to cast
a pointer to or from a long
.
ACE_Time_Value (long sec, long usec = 0);So,
ACE_Time_Value (2.5)
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.
A nice fix would be to add an ACE_Time_Value (double)
constructor. But, that would cause ambiguous overloading
due to the default value for the second argument of
ACE_Time_Value (long sec, long usec = 0)
.
We're stuck with ACE_Time_Value
, but now we
know that it's easy to avoid.
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)Write it like this:
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)
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.
if (test) { // true branch } else { // false branch }
is preferred over:
if (! test) { // false test branch } else { // true test branch }
static_cast<int> (foo)
) instead.
// Disallow copying by not implementing the following . . . ACE_Object_Manager (const ACE_Object_Manager &); ACE_Object_Manager &operator= (const ACE_Object_Manager &);
If the class is a template class, then the
ACE_UNIMPLEMENTED_FUNC
macro should be used:
// = Disallow copying... ACE_UNIMPLEMENTED_FUNC (ACE_TSS (const ACE_TSS<TYPE> &)) ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_TSS<TYPE> &))
ACE_UNIMPLEMENTED_FUNC
can be used with non-template
classes as well. Though for consistency and maximum safety, it
should be avoided for non-template classes.
BOOL
, or similar types.
(ACE_CDR::Boolean
and
CORBA::Boolean
are acceptable). Use the
standard C++ bool
for boolean variables, instead.
-I
)
to include any directory which contains files with template
definitions. The Compaq Tru64 cxx -ptv
compiler option
may help diagnose missing template instantiation problems.
this->
member. 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.
template<typename S_var, size_t BOUND, template <typename> class Insert_Policy> class A {};
ACE_DEBUG
for printouts,
and ACE_OS::fprintf ()
for
file I/O. Avoid using iostreams because of implementation
differences across platforms.
ACE_DEBUG
and
ACE_ERROR
don't support
%ld
of any other multicharacter format.
ACE_TCHAR
instead of char for strings and ACE_TEXT()
around string literals. Exceptions are char
arrays used for data and strings that need to remain as 1
byte characters.
ACE_TCHAR
,
use the ACE_TEXT_CHAR_TO_TCHAR()
macro. If you have a ACE_TCHAR
string that needs to be converted to a char
string, use the
ACE_TEXT_ALWAYS_CHAR()
macro
TCHAR
macros. The wide character-ness of ACE
is separate from UNICODE and _UNICODE.
ACE_TCHAR
or ACE_TEXT
. The CORBA specification
defines APIs as using char. So most of the time there is no need
to use wide characters.
#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; }Output is:
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
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 ACE_wrappers/bin/generate_export_file.pl Perl script.
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.
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++ >=
4.0 since doing so
defeats some neat optimizations. Here's a common case in
where an export macro is generally used unnecessarily:
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(); } };
Here the application is only meant to invoke operations
through a pointer or reference to the abstract base class
"Foo
" created by the "FooFactory
",
not the "Bar
" subclass. In this case,
exporting "Bar
" is unnecessary. If your
concrete class is meant to be used outside of the shared
library (e.g. as a template parameter, within a
dynamic_cast<>
, etc) you must then export
it. Otherwise, avoid doing so if you can.
Make sure that you specify that you are creating a dynamic
library in your MPC file by adding
a sharedname
tag.
Make sure that you add the FOO_BUILD_DLL
preprocessor symbol to the dynamicflags
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 FOO_BUILD_DLL
in their build setup. This
ties back to the first item.
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 -lDependsOnFoo -lFoo
. Note that this
is not a requirement on GNU/Linux but linkers on other
platforms are not as forgiving.
Use the ACE_SINGLETON_DECLARE
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 Bug 2260 for details).
Avoid inlining virtual functions in classes that must be
exported since doing so can cause RTTI related problems
(e.g. dynamic_cast<> failures
) 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.
ACE_OS
namespace functions instead of bare OS system calls.
ACE_OS
namespace are ones that
have direct equivalents on some OS platform. Functions that
are extensions should go in the
ACE
namespace.
ACE_SYNCH_MUTEX
macro,
instead of using one of the specific mutexes, such as
ACE_Thread_Mutex
. This provides
portability between threaded and non-threaded platforms.
ACE_Singleton
,
ACE_TSS_Singleton
, or as an
ACE_Cleanup
object. See the
ACE
Singleton.h
,
Object_Manager.h
, and
Managed_Object.h
header files for more information.
Static instances of built-in types, such as
int
or any pointer type, are fine.
Construction of static instance of a user-defined type should never 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.
ACE_NEW_RETURN (this->name_space_, LOCAL_NAME_SPACE, -1); if (ACE_LOG_MSG->op_status () != 0) ....This snip of code is from
ACE_Naming_Context
.
All failed constructors in ACE (should) call ACE_ERROR. This sets
the thread-specific op_status, 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.
open()
methods on classes that
perform initializations that can fail. This is because open()
returns an error code that's easily checked by the caller,
rather than relying on constructor and thread-specific status
values.
std::swap std::for_each std::fill std::generate std::transform std::copy
ACE_ASSERT
. 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:
ACE_ASSERT (this->next (retv) != 0); // BAD CODE!Instead, the above should be coded this way:
int const result = this->next (retv); ACE_ASSERT (result != 0); ACE_UNUSED_ARG (result);
ACE_DEBUG
code:
ACE_DEBUG ((LM_DEBUG, "handling signal: %d iterations left\n", --this->iterations_)); // BAD CODE!Note that this won't work correctly if
ACE_NDEBUG
is
defined, for the same reason that having side-effects in
ACE_ASSERT
s won't work either, i.e., because
the code is removed.
ACE_HANDLE h = open the file (filename);
ACE_OS::unlink (filename);
This avoids leaving the temporary file even if the program crashes.
THR_BOUND
thread creation
flag for time-critical threads. This ensures that the thread competes
for resources globally on Solaris. It is harmless on other platforms.
<tab> * dir/file.ext [(methods)]: description...If you have a number of files, the names should be on separate lines. In this case, it's also ok to start the description on a new line indented to "dir."
ChangeLogTag: Thu Jul 22 09:55:10 UTC 1999 David L. Levine
<levine@cs.wustl.edu>
man perlstyle
to view it.
PATH
:eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' & eval 'exec perl -S $0 $argv:q' if 0;
#
", unless the first line is "#! /bin/sh
".
With just "#
", t/csh users will spawn a new shell.
That will cause their .[t]cshrc
to be
processed, possibly clobbering a necessary part of
their environment.
require 5.003;
.
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 .
.
Last modified: Wed Nov 23 11:00:44 CST 2005
Back to ACE Documentation Home.