views:

1213

answers:

24

What are your favorite C++ coding style idioms? I'm asking about style or coding typography such as where you put curly braces, are there spaces after keywords, the size of indents, etc. This is opposed to best-practices or requirements such as always deleting arrays with delete[].

Here is an example of one of my favorites: In C++ Class initializers, we put the separators at the front of the line, rather than the back. This makes it easier to keep this up to date. It also means that source code control diffs between versions are cleaner.

TextFileProcessor::
TextFileProcessor( class ConstStringFinder& theConstStringFinder ) 

    : TextFileProcessor_Base( theConstStringFinder )

    , m_ThreadHandle  ( NULL )
    , m_startNLSearch (    0 )
    , m_endNLSearch   (    0 )
    , m_LineEndGetIdx (    0 )
    , m_LineEndPutIdx (    0 )
    , m_LineEnds      ( new const void*[ sc_LineEndSize ] )
{
    ;
}
A: 

Write each method or function argument on a separate line such that it can be easily commented.

int ReturnMaxValue(
    int* inputList,   /* the list of integer values from which to get the maximum */
    long size,        /* count of the number of integer values in inputList */
    char* extraArgs   /* additional arguments that a caller can provide.    */
)
Ather
Use meaningful variable names rather than comments: int ReturnMaxValue(int *inputList, long inputListSize). The comment about extraArgs told me just about as much as the variable name - nothing (yeah, I know it's just an example but it's not a really good one).
Andreas Magnusson
Completely concur with Andreas. If you really need to be documenting your parameters, use Doxygen format.
Austin Ziegler
A: 

Document the return values on the function line, so they are very easy to find.

int function(void) /* return 1 on success, 0 on failure */ 
{
    return 1;
};
EvilTeach
Putting a superfluous semicolon at the end of a block that doesn't need a semicolon is one of my least favorite C++ coding style idioms.
bk1e
feel free to edit it
EvilTeach
This style suggestion doesn't help on anything but the simplest return values.
Austin Ziegler
Nonsense. You can make the comment as large or small as necessary. When the question arises, "What does this thing return?" where do you go? users guide? hpp file? cpp file? If you go look at the function, it's right there. Most IDEs can pick the comment up and show it to you in context.
EvilTeach
Reading thorough the code trying to figure out what a function returns is a squandering of developer time. Do everyone a favor, comment your return values, in a place that is easy to find.
EvilTeach
Doesn't the code need a pair of parentheses `()` after `function`?
ArunSaha
Yes. Thank you.
EvilTeach
+2  A: 

Not sure if this counts as an idiom, but I tend to use doxygen-style inline comments even when the project isn't -yet- using doxygen...

bool MyObjects::isUpToSomething() ///< Is my object up to something

(aside. my comments are not usually quite that lame.)

Roddy
+4  A: 
zerbp
Spelling errors and typos also get corrected in code that I work on!
jussij
+11  A: 

I like lining up code/initializations in 'columns'... Proves very useful when editing with a 'column' mode capable editor and also seems to be a lot easier for me to read...

int myVar        = 1;    // comment 1
int myLongerVar  = 200;  // comment 2

MyStruct arrayOfMyStruct[] = 
{   
    // Name,                 timeout,   valid
    {"A string",             1000,      true    },   // Comment 1
    {"Another string",       2000,      false   },   // Comment 2 
    {"Yet another string",   11111000,  false   },   // Comment 3
    {NULL,                   5,         true    },   // Comment 4
};

In contrast, the same code not indented and formatted as above would appear... (A little harder to read to my eyes)

int myVar = 1; // comment 1
int myLongerVar = 200; // comment 2

MyStruct arrayOfMyStruct[] = 
{   
    // Name, timeout, valid
    {"A string", 1000, true},// Comment 1
    {"Another string", 2000, false }, // Comment 2 
    {"Yet another string", 11111000,false}, // Comment 3
    {NULL, 5, true }, // Comment 4
};
Prembo
This issue with this, is that when one line gets too long, (say you have to add "Yet another string, but this one is longer than the rest"), you either have to break the nice pattern, or reformat everything, leading to a source control nightmare where every line changes.
Eclipse
+4  A: 

No favorites but I will fix code that has:

  1. tabs - causes misalignment in many IDEs and code review tools, because they don't always agree on tab at mod 8 spaces.
  2. lines longer than 80 columns - let's face it, shorter lines are more readable. My brain can parse most coding conventions, as long as the lines are short.
  3. lines with trailing whitespaces - git will complain about it as whitespace errors, which show up as red blobs in diffs, which is annoying.

Here is a one-liner to find the offending files:

git grep -I -E '<tab>|.{81,}|  *$' | cut -f1 -d: | sort -u

where <tab> is the tab character (POSIX regexp doesn't do \t)

ididak
Well TAB characters should be used for indenting, not formatting. Spaces should be used for formatting. That way the code will show up nicely with any TAB width setting. And TABs should be 8 characters anyway.
Terminus
Heh... Trailing whitespace is so annoying! I have to bite my tongue whenever I'm watching someone code and they leave in spaces at the end of the line (say, when breaking a line by putting the cursor after a space and hitting Enter).
Owen
The problem with trailing whitespace is you can't see it.
FryGuy
+21  A: 

When creating enumerations, put them in a namespace so that you can access them with a meaningful name:

namespace EntityType {
    enum Enum {
        Ground = 0,
        Human,
        Aerial,
        Total
    };
}

void foo(EntityType::Enum entityType)
{
    if (entityType == EntityType::Ground) {
        /*code*/
    }
}
kshahar
no semicolon after namespaces required though. is that a typo?
Johannes Schaub - litb
A bad habit :) -fixed
kshahar
How can an answer be "accepted" for such a question ? No offsense to kshahar, it's a good technique, but "accepting" an answer automatically brings it to the top and doesn't let a more democratic evaluation process to take place, which is a shame for a "what's your favorite..." question
Eli Bendersky
I agree with this, except that I generally do it as classes. (This is because I have some code generation that lets me do enum-to-string and string-to-enum conversion automatically.)
Austin Ziegler
+6  A: 

re: ididak

I fix code that breaks long statements into too many short lines.

Let's face it: it's not the 90's any more. If your company can't afford widescreen LCDs for its coders, you need to get a better job :)

Even if your monitor wrapped all the way around your head, shorter lines would be easier for you to take in. Let the code context determine if the line needs to be long; usually it doesn't.
Mark Ransom
I put multiple windows side by side on wide screens. I'd like to be able to (read) code on a laptop as well.
ididak
Most of the time, it shouldn't be necessary to see all of that really long line to understand at a glance what it does.
korona
Okay, let's make it 120 and call it a deal :)
utku_karatas
You get my +1 vote. There are times when wrapping long lines does help, but to automatically wrap a line just because it hits the 80 column mark is just stupid.
jussij
+8  A: 

You are talking about coding style here, not idioms.

Nemanja Trifunovic
+1  A: 

I really like putting a small expression on the same line as an if

int myFunc(int x) {
   if(x >20) return -1;
   //do other stuff ....
}
Yep, good for guard clauses. Nevertheless I always put curly braces around the conditional statement. It has proven to be more maintainable for me.
mxp
I generally don't use the curly braces if I'm doing it all on one line. If the line ends up long enough that I want to break it, though, I add the braces.
Adam Jaskiewicz
A: 

I always nitpick and edit the following:

  • Superfluous newlines
  • No newline at EOF
korona
+2  A: 

It's useful to put function names on a new line, so you can grep like

grep -R '^fun_name' .

for them. I've seen that style used for a loads of GNU projects and like it:

static void
fun_name (int a, int b) {
    /* ... */
}
Johannes Schaub - litb
An alternative that doesn't require this convention: `egrep -r 'main\([^)]*\)\s?\{' .` – admittedly, not nearly as simple, and requires arguments and opening brace on the same line.
Konrad Rudolph
A: 

I usually stick to KNF described in *BSD STYLE(9)

Terminus
+1  A: 

After working with someone who was partly blind - and at his request - I switched to using many more spaces. I didn't like it at the time, but now I prefer it. Off the top of my head, the only place where there isn't whitespace between identifiers and keywords and whatnot is after a function name and before the following parentheses.

void foo( int a, int b )
{
  int c = a + ( a * ( a * b ) );
  if ( c > 12 )
    c += 9;
  return foo( 2, c );
}
Jamie Hale
One guy at my work puts a space before his semicolons. Drives me nuts.
Owen
A: 

I tend to put an else on all of my ifs.

if (condition)
{
    complicated code goes here
}
else
{
    /* This is a comment as to why the else path isn't significant */ 
}

Even though it annoys my coworkers. You can tell at a glance, that I considered the else case during coding.

EvilTeach
If the code in the true case is so complicated, it probably needs to be a separate function/method. That will reduce the need for a useless else block and annoy your coworkers less.
Austin Ziegler
I usually stick it as a comment
franji1
+14  A: 
jalf
Something about exceptions needed, I think.
anon
Added a note on exceptions, and an example
jalf
Came here to say this, +1
Gab Royer
+7  A: 

pImpl: Pointer-to-Implementation

The pImpl idiom is a very useful way to decouple the interface of a class from its implementation.

Normally, a class definition must contain member variables as well as methods, which may expose too much information. For example, a member variable may be of a type defined in a header that we don't wish to include everywhere.

The windows.h header is a prime example here. We may wish to wrap a HANDLE or another Win32 type inside a class, but we can't put a HANDLE in the class definition without having to include windows.h everywhere the class is used.

The solution then is to create a Private IMPLementation or Pointer-to-IMPLementation of the class, and let the public implementation store only a pointer to the private one, and forward all member methods.

For example:

class private_foo; // a forward declaration a pointer may be used

// foo.h
class foo {
public:
  foo();
  ~foo();
  void bar();
private:
  private_foo* pImpl;
};

// foo.cpp
#include whichever header defines the types T and U

// define the private implementation class
class private_foo {
public:
  void bar() { /*...*/ }

private:
  T member1;
  U member2;
};

// fill in the public interface function definitions:
foo::foo() : pImpl(new private_foo()) {}
foo::~foo() { delete pImpl; }
void foo::bar() { pImpl->bar(); }

The implementation of foo is now decoupled from its public interface, so that

  • it can use members and types from other headers without requiring these dependencies to be present when the class is used, and
  • the implementation can be modified without forcing a recompile of the code that uses the class.

Users of the class simply include the header, which contains nothing specific about the implementation of the class. All implementation details are contained inside foo.cpp.

jalf
@jalf, good complete answer.
Rob Wells
A: 

I'd suggest PIMPL or as James Coplien originally called it "Handle Body".

This idiom allows you to completely decouple interface from implementation. When working on the rewrite and re-release of a major CORBA middleware component, this idiom was used to completely decouple the API from the implementation.

This practically eliminated any possibility reverse engineering.

An excellent resource for C++ idioms is James Coplien's excellent book "Advanced C++ Programming Styles and Idioms". Highly recommended!

Edit: As pointed out below by Neil, this book is quite out of date with many of his recommendations actually being incorporated into the C++ standard itself. However, I still find it to be a source of useful info, esp. in the form of his PLoP paper on C++ idioms where many idioms were recast into patterm form.

Rob Wells
The book is completely out of date and has little relevance to modern C++ programmers.
anon
That's James Coplien. The handle/body idiom, while certainly similar wasn't generally used the same way or for the same reasons. It was primarily for reference counting.
Jerry Coffin
I missed the Douglas Coplien mistake - that is actually quite funny. I'd pay to read Microserfs re-written to refer to the original C++ devs!
anon
Given that current implementations of C++ are supposed to be reverse compatible with previous implementations, I think your statement of "completely out of date and has little relevance to modern C++ programmers" to be a bit of an exaggeration. There's still plenty in that book to be useful. Yikes. Must've mixed up Doug Coupland with Cope.
Rob Wells
@Rob Coplien's book came out nearly 20 years ago, long before the language was standardised, and the standard made no guarantees that it was compatible with older implementations - in many was it explicitly wasn't. Also, many of the idioms Coplien mentions have been subsumed into language features, like templates.
anon
@Neil, I agree so I've added a note about the age of the book and a link to his '98 update to the book.
Rob Wells
@Neil: I can't say I completely agree. Quite a bit of code in the book depends on templates (though its use is pretty "tame" by modern standards). The biggest part that's obsolescent is its pervasive use of reference counting. I'd say around 2/3rds of the idioms in the book apply as well today as ever (though you'd often implement them somewhat differently today).
Jerry Coffin
@Jerry Use of templates first appears at page 259 (they are mentioned briefly prior to this) which is about 2/3rds of the way through the main text, and the example is as you say "tame", some may say "naive". But I suppose I must declare that I've never liked this book, and this long-term dislike my be coloring my view. I still find it very difficult to imagine recommending it to a new C++ programmer in 2010.
anon
+6  A: 

CRTP: Curiously Recurring Template Pattern

CRTP happens when you pass a class as a template parameter to its base class:

template<class Derived>
struct BaseCRTP {};

struct Example : BaseCRTP<Example> {};

Within the base class, it can get ahold of the derived instance, complete with the derived type, simply by casting (either static_cast or dynamic_cast work):

template<class Derived>
struct BaseCRTP {
  void call_foo() {
    Derived& self = *static_cast<Derived*>(this);
    self.foo();
  }
};

struct Example : BaseCRTP<Example> {
  void foo() { cout << "foo()\n"; }
};

In effect, call_foo has been injected into the derived class with full access to the derived class's members.

Feel free to edit and add specific examples of use, possibly to other SO posts.

Roger Pate
If ever an idiom had a bad name (and C++ has some lulus) then this has got to be it. I think you should describe at least one of the curious uses for this answer to be useful.
anon
It's called the Curious_ly_ recurring template pattern. That's an adverb: the recurrence is curious, not the pattern :-)
Roger Lipscombe
@Roger Pate: Why post an answer and vote to close?
Jason
I voted to close before the question changed drastically.
Roger Pate
Ah, my mistake.
Jason
+5  A: 

Copy-swap

The copy-swap idiom provides exception-safe copying. It requires that a correct copy ctor and swap are implemented.

struct String {
  String(String const& other);

  String& operator=(String copy) { // passed by value
    copy.swap(*this); // nothrow swap
    return *this; // old resources now in copy, released in its dtor
  }

  void swap(String& other) throw() {
    using std::swap; // enable ADL, defaulting to std::swap
    swap(data_members, other.data_members);
  }

private:
  Various data_members;
};
void swap(String& a, String& b) { // provide non-member for ADL
  a.swap(b);
}

You can also implement the swap method with ADL (Argument Dependent Lookup) directly.

This idiom is important because it handles self-assignment[1], makes the strong exception guarantee[2], and is often very easy to write.


[1] Even though self-assignment isn't handled as efficiently as possible, it's supposed to be rare, so if it never happens, this is actually faster.

[2] If any exception is thrown, the state of the object (*this) is not modified.

RC
Some text explaining why/how/when this is useful, perhaps?
jalf
+2  A: 

I don't know if it qualifies as an idiom, exactly, but quite a bit of heavy-duty template programming depends (often heavily) on SFINAE (substitution failure is not an error). A couple of the answers to a previous question have examples.

Jerry Coffin
I think it qualifies as an idiom. Whether it is among the "most useful" is debatable though. Most C++ programmers probably don't need it very often. Still, +1 from me.
jalf
Combine with showing how boost::enable_if is useful.
Roger Pate
+2  A: 

Compile-time polymorphism

(Also known as syntactic polymorphism and static polymorphism, contrast with runtime polymorphism.)

With template functions, one can write code that relies on type constructors and call signatures of families of parametrized types, without having to introduce a common base class.

In the book Elements of Programming, the authors refer to this treatment of types as abstract genera. With concepts one can specify the requirements on such type parameters, though C++ doesn't mandate such specifications.

Two simple examples:

#include <stdexcept>

template <typename T>
T twice(T n) {
  return 2 * n;
}

InIt find(InIt f, InIt l,
          typename std::iterator_traits<InIt>::reference v)
{
  while (f != l && *f != v)
    ++f;
  return f;
}   

int main(int argc, char* argv[]) {
  if (6 != twice(3))
    throw std::logic_error("3 x 2 = 6");

  int const nums[] = { 1, 2, 3 };
  if (nums + 4 != find(nums, nums + 4, 42))
    throw std::logic_error("42 should not have been found.");

  return 0;
}

One can call twice with any regular type that has a binary * operator defined. Similarly, one can call find() with any types that are comparable and that model Input Iterator. One set of code operates similarly on different types, with no shared base classes in sight.

Of course, what's really going on here is that it's the same source code being expanded into various type-specific functions at template instantiation time, each with separate generated machine code. Accommodating the same set of types without templates would have required either 1) separate hand-written functions with specific signatures, or 2) runtime polymorphism through virtual functions.

seh
+3  A: 

Template and Hook

This is a way to handle as much as possible in a framework and give a door or hook for customization by users of a framework. Also known as Hotspot and Template Method.

class Class {
  void PrintInvoice();     // Called Template (boilerplate) which uses CalcRate()
  virtual void CalcRate() = 0;  // Called Hook
}

class SubClass : public Class {
  virtual void CalcRate();      // Customized method
}

Described by Wolfgang Pree in his book Design Patterns for Object-Oriented Software Development.

epatel
A: 

if/while/for parenthesized expression(s) WITH a space separator

if (expression)  // preferred - if keyword sticks out more

vs.

if(expression)  // looks too much like a void function call

I guess this implies that I like my function calls to NOT have a space separator

foo(parm1, parm2);
franji1