荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: jjksam ([==面壁大师==]), 信区: Program
标  题: C++ FAQ (part 11 of 14)
发信站: 荔园晨风BBS站 (Mon Jul  1 14:36:18 2002), 转信


From: cline@parashift.com
Sender: cline@parashift.com
Newsgroups: comp.lang.c++,comp.answers,news.answers,alt.comp.lang.learn.c-c++
Subject: C++ FAQ (part 11 of 14)
Summary: Please read this before posting to comp.lang.c++
Followup-To: comp.lang.c++
Reply-To: cline@parashift.com (Marshall Cline)
Distribution: world
Approved: news-answers-request@mit.edu
Expires: +1 month

Archive-name: C++-faq/part11
Posting-Frequency: monthly
Last-modified: Jun 17, 2002
URL: http://www.parashift.com/c++-faq-lite/

AUTHOR: Marshall Cline / cline@parashift.com / 972-931-9470

COPYRIGHT: This posting is part of "C++ FAQ Lite."  The entire "C++ FAQ Lite"
document is Copyright(C)1991-2002 Marshall Cline, Ph.D., cline@parashift.com.
All rights reserved.  Copying is permitted only under designated situations.
For details, see section [1].

NO WARRANTY: THIS WORK IS PROVIDED ON AN "AS IS" BASIS.  THE AUTHOR PROVIDES
NO
WARRANTY WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE WORK, INCLUDING
WARRANTIES WITH RESPECT TO ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
PURPOSE.

C++-FAQ-Lite != C++-FAQ-Book: This document, C++ FAQ Lite, is not the same as
the C++ FAQ Book.  The book (C++ FAQs, Cline and Lomow, Addison-Wesley) is
500%
larger than this document, and is available in bookstores.  For details, see
section [3].

==============================================================================

SECTION [25]: Built-in / intrinsic / primitive data types


[25.1] Can sizeof(char) be 2 on some machines? For example, what about
       double-byte characters? [NEW!]

[Recently created inspired by Randy Sherman (in 5/02).]

No, sizeof(char) is always 1.  Always.  It is never 2.  Never, never, never.

Even if you think of a "character" as a multi-byte thingy, char is not.
sizeof(char) is always exactly 1.  No exceptions, ever.

Look, I know this is going to hurt your head, so please, please just read the
next few FAQs in sequence and hopefully the pain will go away by sometime next
week.

==============================================================================

[25.2] What are the units of sizeof? [NEW!]

[Recently created inspired by Randy Sherman (in 5/02).]

Bytes.

For example, if sizeof(Fred) is 8, the distance between two Fred objects in an
array of Freds will be exactly 8 bytes.

As another example, this means sizeof(char) is one[25.1] byte.  That's right:
one byte.  One, one, one, exactly one byte, always one byte.  Never two bytes.
No exceptions.

==============================================================================

[25.3] Whoa, but what about machines or compilers that support multibyte
       characters.  Are you saying that a "character" and a char might be
       different?!? [NEW!]

[Recently created inspired by Randy Sherman (in 5/02).]

Yes that's right: the thing commonly referred to as a "character" might be
different from the thing C++ calls a char.

I'm really sorry if that hurts, but believe me, it's better to get all the
pain
over with at once.  Take a deep breath and repeat after me: "character and
char
might be different." There, doesn't that feel better? No? Well keep reading --
it gets worse.

==============================================================================

[25.4] But, but, but what about machines where a char has more than 8 bits?
       Surely you're not saying a C++ byte might have more than 8 bits, are
       you?!? [NEW!]

[Recently created thanks to Randy Sherman (in 5/02) and removed a superfluous
statement thanks to Gennaro Prota (in 6/02).]

Yep, that's right: a C++ byte might have more than 8 bits.

The C++ language guarantees a byte must always have at least 8 bits.  But
there
are implementations of C++ that have more than 8 bits per byte.

==============================================================================

[25.5] Okay, I could imagine a machine with 9-bit bytes.  But surely not
16-bit
       bytes or 32-bit bytes, right? [NEW!]

[Recently created thanks to Randy Sherman (in 5/02).]

Wrong.

I have heard of one implementation of C++ that has 64-bit "bytes." You read
that right: a byte on that implementation has 64 bits.  64 bits per byte.  64.
As in 8 times 8.

And yes, you're right, combining with the above[25.1] would mean that a char
on
that implementation would have 64 bits.

==============================================================================

[25.6] I'm sooooo confused.  Would you please go over the rules about bytes,
       chars, and characters one more time? [NEW!]

[Recently created thanks to Randy Sherman (in 5/02) and rewrote; changed the
example from the mythical FOO machine to a PDP-10, plus added words showing
how
to simulate pointers using software, much thanks to Andrew Koenig (in 6/02).]

Here are the rules:
 * The C++ language gives the programmer the impression that memory is laid
out
   as a sequence of something C++ calls "bytes."
 * Each of these things that the C++ language calls a byte has at least 8 bits,

   but might have more than 8 bits.
 * The C++ language guarantees that a char* (char pointers) can address
   individual bytes.
 * The C++ language guarantees there are no bits between two bytes.  This
means
   every bit in memory is part of a byte.  If you grind your way through
memory
   via a char*, you will be able to see every bit.
 * The C++ language guarantees there are no bits that are part of two distinct
   bytes.  This means if you change a particular byte, it will not effect the
   value of any other byte in the system.
 * The C++ language gives you a way to find out how many bits are in a byte in
   your particular implementation: include the header <climits>, then the
   actual number of bits per byte will be given by the CHAR_BIT macro.

Let's work an example to illustrate these rules.  The PDP-10 has 36-bit words
with no hardware facility to address anything within one of those words.  That
means a pointer can point only at things on a 36-bit boundary: it is not
possible for a pointer to point 8 bits to the right of where some other
pointer
points.

One way to abide by all the above rules is for a PDP-10 C++ compiler to define
a "byte" as 36 bits.  Another valid approach would be to define a "byte" as 9
bits, and simulate a char* by two words of memory: the first could point to
the
36-bit word, the second could be a bit-offset within that word.  In that case,
the C++ compiler would need to add extra instructions when compiling code
using
char* pointers.  For example, the code generated for *p = 'x' might read the
word into a register, then use bit-masks and bit-shifts to change the
appopriate 9-bit byte within that word.  An int* could still be implemented as
a single hardware pointer, since C++ allows sizeof(char*) != sizeof(int*).

Using the same logic, it would also be possible to define a PDP-10 C++ "byte"
as 12-bits or 18-bits.  However the above technique wouldn't allow us to
define
a PDP-10 C++ "byte" as 8-bits, since 8*4 is 32, meaning every 4th byte we
would
skip 4 bits.  A more complicated approach could be used for those 4 bits, e.g.,

by packing nine bytes (of 8-bits each) into two adjacent 36-bit words.  The
important point here is that memcpy() has to be able to see every bit of
memory: there can't be any bits between two adjacent bytes.

Note: one of the popular non-C/C++ approaches on the PDP-10 was to pack 5
bytes
(of 7-bits each) into each 36-bit word.  However this won't work in C or C++
since 5*7 = 35, meaning using char*s to walk through memory would "skip" a bit
every fifth byte (and also because C++ requires bytes to have at least 8 bits).


==============================================================================

[25.7] What is a "POD type"? [NEW!]

[Recently created (in 5/02) and added note that POD types can contain
non-virtual member functions thanks to Andrew Koenig (in 6/02).]

A type that consists of nothing but Plain Old Data.

A POD type is a C++ type that has an equialent in C, and that uses the same
rules as C uses for initialization, copying, layout, and addressing.

As an example, the C declaration "struct Fred x;" does not initialize the
members of the Fred variable x.  To make this same behavior happen in C++,
Fred
would need to not have any constructors.  Similarly to make the C++ version of
copying the same as the C version, the C++ Fred must not have overloaded the
assignment operator.  To make sure the other rules match, the C++ version must
not have virtual functions, base classes, non-static members that are private
or protected, or a destructor.  It can, however, have static data members,
static member functions, and non-static non-virtual member functions.

The actual definition of a POD type is recursive and gets a little gnarly.
Here's a slightly simplified definition of POD: a POD type's non-static data
members must be public and can be of any of these types: bool, any numeric
type
including the various char variants, any enumeration type, any data-pointer
type (that is, any type convertible to void*), any pointer-to-function type,
or
any POD type, including arrays of any of these.  Note: data-pointers and
pointers-to-function are okay, but pointers-to-member[32] are not.  Also note
that references are not allowed.  In addition, a POD type can't have
constructors, virtual functions, base classes, or an overloaded assignment
operator.

==============================================================================

[25.8] When initializing non-static data members of built-in / intrinsic /
       primitive types, should I use the "initialization list" or assignment?
       [NEW!]

[Recently created (in 5/02) and clarified the cross-reference (in 6/02).]

For symmetry, it is usually best to initialize all non-static data members in
the constructor's "initialization list," even those that are of a built-in /
intrinsic / primitive type.  The FAQ shows you why and how[10.6].

==============================================================================

[25.9] When initializing static data members of built-in / intrinsic /
       primitive types, should I worry about the "static initialization order
       fiasco"? [NEW!]

[Recently created (in 5/02) and made it clearer that the FAQ provides a
solution (in 6/02).]

Yes, if you initialize your built-in / intrinsic / primitive variable is
initialized by something other than a value that can be computed solely at
compile-time.  The FAQ provides several solutions[10.15] for this (subtle!)
problem.

==============================================================================

[25.10] Can I define an operator overload that works with built-in / intrinsic
        / primitive types? [NEW!]

[Recently created (in 5/02).]

No, the C++ language requires that your operator overloads take at least one
operand of a "class type." The C++ language will not let you define an
operator
all of whose operands / parameters are of primitive types.

For example, you can't define an operator== that takes two char*s and uses
string comparison[13.6].  That's good news because if s1 and s2 are of type
char*, the expression s1 == s2 already has a well defined meaning: it compares
the two pointers, not the two strings pointed to by those pointers.  You
shouldn't use pointers anyway.  Use std::string instead of char*.[17.5]

If C++ let you redefine the meaning of operators on built-in types, you
wouldn't ever know what 1 + 1 is: it would depend on which headers got
included
and whether one of those headers redefined addition to mean, for example,
subtraction.

==============================================================================

[25.11] When I delete an array of some built-in / intrinsic / primitive type,
        why can't I just say delete a instead of delete[] a? [NEW!]

[Recently created (in 5/02).]

Because you can't.

Look, please don't write me an email asking me why C++ is what it is.  It just
is.  If you really want a rationale, buy Bjarne Stroustrup's excellent book,
"Design and Evolution of C++" (Addison-Wesley publishers).  But if your real
goal is to write some code, don't waste too much time figuring out why C++ has
these rules, and instead just abide by its rules.

So here's the rule: if a points to an array of thingies that was allocated via
new T[n], then you must, must, must[16.12] delete it via delete[] a.  Even if
the elements in the array are built-in types.  Even if they're of type char or
int or void*.  Even if you don't understand why.

==============================================================================

[25.12] How can I tell if an integer is a power of two without looping? [NEW!]

[Recently created thanks to S.K. Mody (in 6/02).]

 inline bool isPowerOf2(int i)
 {
   return i > 0 && (i & (i - 1)) == 0;
 }

==============================================================================

SECTION [26]: Coding standards


[26.1] What are some good C++ coding standards?

Thank you for reading this answer rather than just trying to set your own
coding standards.

But beware that some people on comp.lang.c++ are very sensitive on this issue.
Nearly every software engineer has, at some point, been exploited by someone
who used coding standards as a "power play." Furthermore some attempts to set
C++ coding standards have been made by those who didn't know what they were
talking about, so the standards end up being based on what was the
state-of-the-art when the standards setters were writing code.  Such
impositions generate an attitude of mistrust for coding standards.

Obviously anyone who asks this question wants to be trained so they don't run
off on their own ignorance, but nonetheless posting a question such as this
one
to comp.lang.c++ tends to generate more heat than light.

==============================================================================

[26.2] Are coding standards necessary? Are they sufficient?

Coding standards do not make non-OO programmers into OO programmers; only
training and experience do that.  If coding standards have merit, it is that
they discourage the petty fragmentation that occurs when large organizations
coordinate the activities of diverse groups of programmers.

But you really want more than a coding standard.  The structure provided by
coding standards gives neophytes one less degree of freedom to worry about,
which is good.  However pragmatic guidelines should go well beyond
pretty-printing standards.  Organizations need a consistent philosophy of
design and implementation.  E.g., strong or weak typing? references or
pointers
in interfaces? stream I/O or stdio? should C++ code call C code? vice versa?
how should ABCs[22.3] be used? should inheritance be used as an implementation
technique or as a specification technique? what testing strategy should be
employed? inspection strategy? should interfaces uniformly have a get() and/or
set() member function for each data member? should interfaces be designed from
the outside-in or the inside-out? should errors be handled by try/catch/throw
or by return codes? etc.

What is needed is a "pseudo standard" for detailed design. I recommend a
three-pronged approach to achieving this standardization: training,
mentoring[27.1], and libraries.  Training provides "intense instruction,"
mentoring allows OO to be caught rather than just taught, and high quality C++
class libraries provide "long term instruction." There is a thriving
commercial
market for all three kinds of "training." Advice by organizations who have
been
through the mill is consistent: Buy, Don't Build. Buy libraries, buy training,
buy tools, buy consulting.  Companies who have attempted to become a
self-taught tool-shop as well as an application/system shop have found success
difficult.

Few argue that coding standards are "ideal," or even "good," however they are
necessary in the kind of organizations/situations described above.

The following FAQs provide some basic guidance in conventions and styles.

==============================================================================

[26.3] Should our organization determine coding standards from our C
       experience?

No!

No matter how vast your C experience, no matter how advanced your C expertise,
being a good C programmer does not make you a good C++ programmer.  Converting
from C to C++ is more than just learning the syntax and semantics of the ++
part of C++.  Organizations who want the promise of OO, but who fail to put
the
"OO" into "OO programming", are fooling themselves; the balance sheet will
show
their folly.

C++ coding standards should be tempered by C++ experts.  Asking comp.lang.c++
is a start.  Seek out experts who can help guide you away from pitfalls.  Get
training.  Buy libraries and see if "good" libraries pass your coding
standards.  Do not set standards by yourself unless you have considerable
experience in C++.  Having no standard is better than having a bad standard,
since improper "official" positions "harden" bad brain traces.  There is a
thriving market for both C++ training and libraries from which to pull
expertise.

One more thing: whenever something is in demand, the potential for charlatans
increases.  Look before you leap.  Also ask for student-reviews from past
companies, since not even expertise makes someone a good communicator.
Finally, select a practitioner who can teach, not a full time teacher who has
a
passing knowledge of the language/paradigm.

==============================================================================

[26.4] What's the difference between <xxx> and <xxx.h> headers?

The headers in ISO Standard C++ don't have a .h suffix.  This is something the
standards committee changed from former practice.  The details are different
between headers that existed in C and those that are specific to C++.

The C++ standard library is guaranteed to have 18 standard headers from the C
language.  These headers come in two standard flavors, <cxxx> and <xxx.h>
(where xxx is the basename of the header, such as stdio, stdlib, etc).  These
two flavors are identical except the <cxxx> versions provide their
declarations
in the std namespace only, and the <xxx.h> versions make them available both
in
std namespace and in the global namespace.  The committee did it this way so
that existing C code could continue to be compiled in C++.  However the <xxx.
h>
versions are deprecated, meaning they are standard now but might not be part
of
the standard in future revisions.  (See clause D.5 of the ISO C++
standard[6.12].)

The C++ standard library is also guaranteed to have 32 additional standard
headers that have no direct counterparts in C, such as <iostream>, <string>,
and <new>.  You may see things like #include <iostream.h> and so on in old
code, and some compiler vendors offer .h versions for that reason.  But be
careful: the .h versions, if available, may differ from the standard versions.
And if you compile some units of a program with, for example, <iostream> and
others with <iostream.h>, the program may not work.

For new projects, use only the <xxx> headers, not the <xxx.h> headers.

When modifying or extending existing code that uses the old header names, you
should probably follow the practice in that code unless there's some important
reason to switch to the standard headers (such as a facility available in
standard <iostream> that was not available in the vendor's <iostream.h>).  If
you need to standardize existing code, make sure to change all C++ headers in
all program units including external libraries that get linked in to the final
executable.

All of this affects the standard headers only.  You're free to name your own
headers anything you like; see [26.8].

==============================================================================

[26.5] Is the ?: operator evil since it can be used to create unreadable code?

No, but as always, remember that readability is one of the most important
things.

Some people feel the ?: ternary operator should be avoided because they find
it
confusing at times compared to the good old if statement.  In many cases ?:
tends to make your code more difficult to read (and therefore you should
replace those usages of ?: with if statements), but there are times when the ?:

operator is clearer since it can emphasize what's really happening, rather
than
the fact that there's an if in there somewhere.

Let's start with a really simple case.  Suppose you need to print the result
of
a function call.  In that case you should put the real goal (printing) at the
beginning of the line, and bury the function call within the line since it's
relatively incidental (this left-right thing is based on the intuitive notion
that most developers think the first thing on a line is the most important
thing):

 // Preferred (emphasizes the major goal -- printing):
 std::cout << funct();

 // Not as good (emphasizes the minor goal -- a function call):
 functAndPrintOn(std::cout);

Now let's extend this idea to the ?: operator.  Suppose your real goal is to
print something, but you need to do some incidental decision logic to figure
out what should be printed.  Since the printing is the most important thing
conceptually, we prefer to put it first on the line, and we prefer to bury the
incidental decision logic.  In the example code below, variable n represents
the number of senders of a message; the message itself is being printed to
std::cout:

 int n = /*...*/;   // number of senders

 // Preferred (emphasizes the major goal -- printing):
 std::cout << "Please get back to " << (n==1 ? "me" : "us") << " soon!\n";

 // Not as good (emphasizes the minor goal -- a decision):
 std::cout << "Please get back to ";
 if (n == 1)
   std::cout << "me";
 else
   std::cout << "us";
 std::cout << " soon!\n";

All that being said, you can get pretty outrageous and unreadable code ("write
only code") using various combinations of ?:, &&, ||, etc.  For example,

 // Preferred (obvious meaning):
 if (f())
   g();

 // Not as good (harder to understand):
 f() && g();

Personally I think the explicit if example is clearer since it emphasizes the
major thing that's going on (a decision based on the result of calling f())
rather than the minor thing (calling f()).  In other words, the use of if here
is good for precisely the same reason that it was bad above: we want to major
on the majors and minor on the minors.

In any event, don't forget that readability is the goal (at least it's one of
the goals).  Your goal should not be to avoid certain syntactic constructs
such
as ?: or && or || or if -- or even goto.  If you sink to the level of a
"Standards Bigot," you'll ultimately embarass yourself since there are always
counterexamples to any syntax-based rule.  If on the other hand you emphasize
broad goals and guidelines (e.g., "major on the majors," or "put the most
important thing first on the line," or even "make sure your code is obvious
and
readable"), you're usually much better off.

Code must be written to be read, not by the compiler, but by another human
being.

==============================================================================

[26.6] Should I declare locals in the middle of a function or at the top?

Declare near first use.

An object is initialized (constructed) the moment it is declared.  If you
don't
have enough information to initialize an object until half way down the
function, you should create it half way down the function when it can be
initialized correctly.  Don't initialize it to an "empty" value at the top
then
"assign" it later.  The reason for this is runtime performance.  Building an
object correctly is faster than building it incorrectly and remodeling it
later.  Simple examples show a factor of 350% speed hit for simple classes
like
String.  Your mileage may vary; surely the overall system degradation will be
less that 350%, but there will be degradation.  Unnecessary degradation.

A common retort to the above is: "we'll provide set() member functions for
every datum in our objects so the cost of construction will be spread out."
This is worse than the performance overhead, since now you're introducing a
maintenance nightmare.  Providing a set() member function for every datum is
tantamount to public data: you've exposed your implementation technique to the
world.  The only thing you've hidden is the physical names of your member
objects, but the fact that you're using a List and a String and a float, for
example, is open for all to see.

Bottom line: Locals should be declared near their first use.  Sorry that this
isn't familiar to C experts, but new doesn't necessarily mean bad.

==============================================================================

[26.7] What source-file-name convention is best? foo.cpp? foo.C? foo.cc?

If you already have a convention, use it.  If not, consult your compiler to
see
what the compiler expects.  Typical answers are: .cpp, .C, .cc, or .cxx
(naturally the .C extension assumes a case-sensitive file system to
distinguish
.C from .c).

We've often used .cpp for our C++ source files, and we have also used .C.  In
the latter case, when porting to case-insensitive file systems you need to
tell
the compiler to treat .c files as if they were C++ source files (e.g., -Tdp
for
IBM CSet++, -cpp for Zortech C++, -P for Borland C++, etc.).

The point is that none of these filename extensions are uniformly superior to
the others.  We generally use whichever technique is preferred by our customer
(again, these issues are dominated by business considerations, not by
technical
considerations).

==============================================================================

[26.8] What header-file-name convention is best? foo.H? foo.hh? foo.hpp?

If you already have a convention, use it.  If not, and if you don't need your
editor to distinguish between C and C++ files, simply use .h.  Otherwise use
whatever the editor wants, such as .H, .hh, or .hpp.

We've tended to use either .hpp or .h for our C++ header files.

==============================================================================

[26.9] Are there any lint-like guidelines for C++?

Yes, there are some practices which are generally considered dangerous.
However none of these are universally "bad," since situations arise when even
the worst of these is needed:
 * A class Fred's assignment operator should return *this as a Fred& (allows
   chaining of assignments)
 * A class with any virtual[20] functions ought to have a virtual
   destructor[20.5]
 * A class with any of {destructor, assignment operator, copy constructor}
   generally needs all 3
 * A class Fred's copy constructor and assignment operator should have const
in
   the parameter: respectively Fred::Fred(const Fred&) and
   Fred& Fred::operator= (const Fred&)
 * When initializing an object's member objects in the constructor, always use
   initialization lists rather than assignment.  The performance difference
for
   user-defined classes can be substantial (3x!)
 * Assignment operators should make sure that self assignment[12.1] does
   nothing, otherwise you may have a disaster[12.2].  In some cases, this may
   require you to add an explicit test to your assignment operators[12.3].
 * In classes that define both += and +, a += b and a = a + b should generally
   do the same thing; ditto for the other identities of built-in/intrinsic
   types (e.g., a += 1 and ++a; p[i] and *(p+i); etc).  This can be enforced
by
   writing the binary operations using the op= forms.  E.g.,

    Fred operator+ (const Fred& a, const Fred& b)
    {
      Fred ans = a;
      ans += b;
      return ans;
    }

   This way the "constructive" binary operators don't even need to be
friends[14].  But it is sometimes possible to more efficiently implement
common
operations (e.g., if class Fred is actually std::string, and += has to
reallocate/copy string memory, it may be better to know the eventual length
from the beginning).

==============================================================================

[26.10] Why do people worry so much about pointer casts and/or reference
casts?

Because they're evil[6.14]! (Use them sparingly and with great care.)

For some reason, programmers are sloppy in their use of pointer casts.  They
cast this to that all over the place, then they wonder why things don't quite
work right.  Here's the worst thing: when the compiler gives them an error
message, they add a cast to "shut the compiler up," then they "test it" to see
if it seems to work.  If you have a lot of pointer casts or reference casts,
read on.

The compiler will often be silent when you're doing pointer-casts and/or
reference casts.  Pointer-casts (and reference-casts) tend to shut the
compiler
up.  I think of them as a filter on error messages: the compiler wants to
complain because it sees you're doing something stupid, but it also sees that
it's not allowed to complain due to your pointer-cast, so it drops the error
message into the bit-bucket.  It's like putting duct tape on the compiler's
mouth: it's trying to tell you something important, but you've intentionally
shut it up.

A pointer-cast says to the compiler, "Stop thinking and start generating code;
I'm smart, you're dumb; I'm big, you're little; I know what I'm doing so just
pretend this is assembly language and generate the code." The compiler pretty
much blindly generates code when you start casting -- you are taking control
(and responsibility!) for the outcome.  The compiler and the language reduce
(and in some cases eliminate!) the guarantees you get as to what will happen.
You're on your own.

By way of analogy, even if it's legal to juggle chainsaws, it's stupid.  If
something goes wrong, don't bother complaining to the chainsaw manufacturer --
you did something they didn't guarantee would work.  You're on your own.

(To be completely fair, the language does give you some guarantees when you
cast, at least in a limited subset of casts.  For example, it's guaranteed to
work as you'd expect if the cast happens to be from an object-pointer (a
pointer to a piece of data, as opposed to a pointer-to-function or
pointer-to-member) to type void* and back to the same type of object-pointer.
But in a lot of cases you're on your own.)

==============================================================================

[26.11] Which is better: identifier names that_look_like_this or identifier
        names thatLookLikeThis?

It's a precedent thing.  If you have a Pascal or Smalltalk background,
youProbablySquashNamesTogether like this.  If you have an Ada background,
You_Probably_Use_A_Large_Number_Of_Underscores like this.  If you have a
Microsoft Windows background, you probably prefer the "Hungarian" style which
means you jkuidsPrefix vndskaIdentifiers ncqWith ksldjfTheir nmdsadType.  And
then there are the folks with a Unix C background, who abbr evthng n use vry
srt idntfr nms.  (AND THE FORTRN PRGMRS LIMIT EVRYTH TO SIX LETTRS.)

So there is no universal standard.  If your project team has a particular
coding standard for identifier names, use it.  But starting another Jihad over
this will create a lot more heat than light.  From a business perspective,
there are only two things that matter: The code should be generally readable,
and everyone on the team should use the same style.

Other than that, th difs r minr.

One more thing: don't import a coding style onto platform-specific code where
it is foreign.  For example, a coding style that seems natural while using a
Microsoft library might look bizarre and random while using a UNIX library.
Don't do it.  Allow different styles for different platforms.  (Just in case
someone out there isn't reading carefully, don't send me email about the case
of common code that is designed to be used/ported to several platforms, since
that code wouldn't be platform-specific, so the above "allow different styles"
guideline doesn't even apply.)

Okay, one more.  Really.  Don't fight the coding styles used by automatically
generated code (e.g., by tools that generate code).  Some people treat coding
standards with religious zeal, and they try to get tools to generate code in
their local style.  Forget it: if a tool generates code in a different style,
don't worry about it.  Remember money and time?!? This whole coding standard
thing was supposed to save money and time; don't turn it into a "money pit."

==============================================================================

[26.12] Are there any other sources of coding standards?

Yep, there are several.

Here are a few sources that you might be able to use as starting points for
developing your organization's coding standards (in random order):
 * cdfsga.fnal.gov/computing/coding_guidelines/CodingGuidelines.html
 * www.nfra.nl/~seg/cppStdDoc.html
 * www.cs.umd.edu/users/cml/resources/cstyle
 * www.cs.rice.edu/~dwallach/CPlusPlusStyle.html
 * cpptips.hyperformix.com/conventions/cppconventions_1.html
 * www.objectmentor.com/resources/articles/naming.htm
 * www.arcticlabs.com/codingstandards/
 * www.possibility.com/cpp/CppCodingStandard.html
 * www.cs.umd.edu/users/cml/cstyle/Wildfire-C++Style.html
 * The Ellemtel coding guidelines are available at
   - www.cs.umd.edu/users/cml/cstyle/Ellemtel-rules.html
   - www.doc.ic.ac.uk/lab/cplus/c++.rules/
   - www.mgl.co.uk/people/kirit/cpprules.html

Note: I do NOT warrant or endorse these URLs and/or their contents.  They are
listed as a public service only.  I haven't checked their details, so I don't
know if they'll help you or hurt you.  Caveat emptor.

==============================================================================

[26.13] Should I use "unusual" syntax?

Only when there is a compelling reason to do so.  In other words, only when
there is no "normal" syntax that will produce the same end-result.

Software decisions should be made based on money.  Unless you're in an ivory
tower somewhere, when you do something that increases costs, increases risks,
increases time, or, in a constrained environment, increases the product's
space/speed costs, you've done something "bad." In your mind you should
translate all these things into money.

Because of this pragmatic, money-oriented view of software, programmers should
avoid non-mainstream syntax whenever there exists a "normal" syntax that would
be equivalent.  If a programmer does something obscure, other programmers are
confused; that costs money.  These other programmers will probably introduce
bugs (costs money), take longer to maintain the thing (money), have a harder
time changing it (missing market windows = money), have a harder time
optimizing it (in a constrained environment, somebody will have to spend money
for more memory, a faster CPU, and/or a bigger battery), and perhaps have
angry
customers (money).  It's a risk-reward thing: using abnormal syntax carries a
risk, but when an equivalent, "normal" syntax would do the same thing, there
is
no "reward" to ameliorate that risk.

For example, the techniques used in the Obfuscated C Code Contest
<http://www.ioccc.org/> are, to be polite, non-normal.  Yes many of them are
legal, but not everything that is legal is moral.  Using strange techniques
will confuse other programmers.  Some programmers love to "show off" how far
they can push the envelope, but that puts their ego above money, and that's
unprofessional.  Frankly anybody who does that ought to be fired.  (And if you
think I'm being "mean" or "cruel," I suggest you get an attitude adjustment.
Remember this: your company hired you to help it, not to hurt it, and anybody
who puts their own personal ego-trips above their company's best interest
simply ought to be shown the door.)

As an example of non-mainstream syntax, it's not "normal" to use the ?:
operator as a statement.  (Some people don't even like it as an expression,
but
everyone must admit that there are a lot of uses of ?: out there, so it is
"normal" (as an expression) whether people like it or not[26.5].) Here is an
example of using using ?: as a statement:

 blah();
 blah();
 xyz() ? foo() : bar();  // should replace with if/else
 blah();
 blah();

Same goes with using || and && as if they are "if-not" and "if" statements,
respectively.  Yes, those are idioms in Perl, but C++ is not Perl and using
these as replacements for if statements (as opposed to using them as
expressions) is just not "normal" in C++.  Example:

 foo() || bar();  // should replace with if (!foo()) bar();
 foo() && bar();  // should replace with if (foo()) bar();

Here's another example that seems to work and may even be legal, but it's
certainly not normal:

 void f(const& MyClass x)  // use const MyClass& x instead
 {
   ...
 }

==============================================================================

SECTION [27]: Learning OO/C++


[27.1] What is mentoring?

It's the most important tool in learning OO.

Object-oriented thinking is caught, not just taught.  Get cozy with someone
who
really knows what they're talking about, and try to get inside their head and
watch them solve problems.  Listen.  Learn by emulating.

If you're working for a company, get them to bring someone in who can act as a
mentor and guide.  We've seen gobs and gobs of money wasted by companies who
"saved money" by simply buying their employees a book ("Here's a book; read it
over the weekend; on Monday you'll be an OO developer").

==============================================================================

[27.2] Should I learn C before I learn OO/C++?

Don't bother.

If your ultimate goal is to learn OO/C++ and you don't already know C, reading
books or taking courses in C will not only waste your time, but it will teach
you a bunch of things that you'll explicitly have to un-learn when you finally
get back on track and learn OO/C++ (e.g., malloc()[16.3], printf()[15.1],
unnecessary use of switch statements[20], error-code exception handling[17],
unnecessary use of #define macros[9.3], etc.).

If you want to learn OO/C++, learn OO/C++.  Taking time out to learn C will
waste your time and confuse you.

==============================================================================

[27.3] Should I learn Smalltalk before I learn OO/C++?

Don't bother.

If your ultimate goal is to learn OO/C++ and you don't already know Smalltalk,
reading books or taking courses in Smalltalk will not only waste your time,
but
it will teach you a bunch of things that you'll explicitly have to un-learn
when you finally get back on track and learn OO/C++ (e.g., dynamic
typing[29.3], non-subtyping inheritance[29.5], error-code exception
handling[17], etc.).

Knowing a "pure" OO language doesn't make the transition to OO/C++ any easier.
This is not a theory; we have trained and mentored literally thousands of
software professionals in OO.  In fact, Smalltalk experience can make it
harder
for some people: they need to unlearn some rather deep notions about typing
and
inheritance in addition to needing to learn new syntax and idioms.  This
unlearning process is especially painful and slow for those who cling to
Smalltalk with religious zeal ("C++ is not like Smalltalk, therefore C++ is
evil").

If you want to learn OO/C++, learn OO/C++.  Taking time out to learn Smalltalk
will waste your time and confuse you.

Note: I sit on both the ANSI C++ (X3J16) and ANSI Smalltalk (X3J20)
standardization committees[6.11].  I am not a language bigot[6.4].  I'm not
saying C++ is better or worse than Smalltalk; I'm simply saying that they are
different[29.1].

==============================================================================

[27.4] Should I buy one book, or several?

At least three.

There are three categories of insight and knowledge in OO programming using
C++.  You should get a great book from each category, not an okay book that
tries to do an okay job at everything.  The three OO/C++ programming
categories
are:
 * C++ legality guides -- what you can and can't do in C++[27.6].
 * C++ morality guides -- what you should and shouldn't do in C++[27.5].
 * Programming-by-example guides -- show lots of examples, normally making
   liberal use of the C++ standard library[27.7].

Legality guides describe all language features with roughly the same level of
emphasis; morality guides focus on those language features that you will use
most often in typical programming tasks.  Legality guides tell you how to get
a
given feature past the compiler; morality guides tell you whether or not to
use
that feature in the first place.

Meta comments:
 * Don't trade off these categories against each other.  You shouldn't argue
in
   favor of one category over the other.  They dove-tail.
 * The "legality" and "morality" categories are both required.  You must have
a
   good grasp of both what can be done and what should be done.

There is a fourth category you should consider in addition to the above three:
OO Design books[27.8].  These are books that focus on how to think and design
with objects.

==============================================================================

[27.5] What are some best-of-breed C++ morality guides?

Here's my personal (subjective and selective) short-list of must-read C++
morality guides, alphabetically by author:
 * Cline, Lomow, and Girou, C++ FAQs, Second Edition, 587 pgs, Addison-Wesley,
   1999, ISBN 0-201-30983-1.  Covers around 500 topics in a FAQ-like Q&A
   format.
 * Meyers, Effective C++, Second Edition, 224 pgs, Addison-Wesley, 1998, ISBN
   0-201-92488-9.  Covers 50 topics in a short essay format.
 * Meyers, More Effective C++, 336 pgs, Addison-Wesley, 1996, ISBN
   0-201-63371-X.  Covers 35 topics in a short essay format.

Similarities: All three books are extensively illustrated with code examples.
All three are excellent, insightful, useful, gold plated books.  All three
have
excellent sales records.

Differences: Cline/Lomow/Girou's examples are complete, working programs
rather
than code fragments or standalone classes.  Meyers contains numerous
line-drawings that illustrate the points.

==============================================================================

[27.6] What are some best-of-breed C++ legality guides?

Here's my personal (subjective and selective) short-list of must-read C++
legality guides, alphabetically by author:
 * Lippman and Lajoie, C++ Primer, Third Edition, 1237 pgs, Addison-Wesley,
   1998, ISBN 0-201-82470-1.  Very readable/approachable.
 * Stroustrup, The C++ Programming Language, Third Edition, 911 pgs,
   Addison-Wesley, 1998, ISBN 0-201-88954-4.  Covers a lot of ground.

Similarities: Both books are excellent overviews of almost every language
feature.  I reviewed them for back-to-back issues of C++ Report, and I said
that they are both top notch, gold plated, excellent books.  Both have
excellent sales records.

Differences: If you don't know C, Lippman's book is better for you.  If you
know C and you want to cover a lot of ground quickly, Stroustrup's book is
better for you.

==============================================================================

[27.7] What are some best-of-breed C++ programming-by-example guides?

Here's my personal (subjective and selective) short-list of must-read C++
programming-by-example guides:
 * Koenig and Moo, Accelerated C++, 336 pgs, Addison-Wesley, 2000, ISBN
   0-201-70353-X.  Lots of examples using the standard C++ library.  Truly a
   programming-by-example book.
 * Musser, STL Tutorial and Reference Guide, Addison-Wesley, 2001.  Lots of
   examples showing how to use the STL portion of the standard C++ library,
   plus lots of nitty gritty detail.

==============================================================================

[27.8] Are there other OO books that are relevant to OO/C++?

Yes! Tons!

The morality[27.5], legality[27.6], and by-example[27.7] categories listed
above were for OO programming.  The areas of OO analysis and OO design are
also
relevant, and have their own best-of-breed books.

There are tons and tons of good books in these other areas.  The seminal book
on OO design patterns is (in my personal, subjective and selective, opinion) a
must-read book: Gamma et al., Design Patterns, 395 pgs, Addison-Wesley, 1995,
ISBN 0-201-63361-2.  Describes "patterns" that commonly show up in good OO
designs.  You must read this book if you intend to do OO design work.

==============================================================================


--
   mm       ★__      __  __ __★______ ______ __  __★
/^(  )^\      █      █  █/    █____ █__█ █∨█
\,(..),/  ▅__█  ▅__█  █\__  ▂__█ █  █ █  █
  V~~V   ▇▆▅▃▁I'm a bat. I'm very bad!^Q^_▃▄▆▇ 你好!^_^欢迎大家到linux

※ 修改:·jjksam 於 Jul  1 14:44:00 修改本文·[FROM: 192.168.0.146]
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.146]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店