Brian R. Bondy
Brian R. Bondy

Reputation: 347216

What are some C++ related idioms, misconceptions, and gotchas that you've learnt from experience?

What are some C++ related idioms, misconceptions, and gotchas that you've learnt from experience?

An example:

class A
{
  public: 
  char s[1024];
  char *p;

  A::A()
  {
    p = s;
  }

  void changeS() const
  {
    p[0] = 'a';
  }

};

Even know changeS is a const member function, it is changing the value of the object. So a const member function only means that it will treat all variables as const, and it does not mean that it will actually keep all members const. (why? the const keyword on the member function treats char *p; as char * const p; And not as const char *p;

Which therefore means that p can't point to something else. And not that you can't change p's data.

Upvotes: 27

Views: 3359

Answers (16)

amit kumar
amit kumar

Reputation: 21012

Do not fall into the trap of using std::noncopyable unless needed. Yes, it is useful at a lot of places, and should be used there.

The trap is that one starts writing clone() function along with making it noncopyable, which implements the same functionality. Instead, you can also use explicit (link) for the copy constructor instead to prevent accidental copying (and make assignment private, or delete the function in C++0x). clone() is needed for inherited base classes though.

Upvotes: 0

amit kumar
amit kumar

Reputation: 21012

Use boost::spirit::hold_any (link) instead of boost::any for performance code (while holding a large number of small objects). I saw a large difference in their performances.

Upvotes: 0

amit kumar
amit kumar

Reputation: 21012

Do not prefer to use shared_ptr unless needed. Prefer using C++ references and unique_ptr instead. shared_ptr is a performance hog and makes the code look more complex than it is. Normally this won't be an issue, except for the unusual attractiveness of shared_ptr and its contagious nature.

Upvotes: 0

Assaf Lavie
Assaf Lavie

Reputation: 75973

You don't need to know C++'s complicated function typedef declaration syntax. Here's a cute trick I found.

Quick, describe this typedef:

typedef C &(__cdecl C::* const CB )(const C &) const;

Easy! CB is a pointer to a member function of class C accepting a const reference to a C object and returning a non-const reference to a C object. Oh, and it’s a const member function. Oh, and the function pointer itself is const… (Right?)

The C++ function declaration specification syntax is notoriously obtuse and hard to remember. Yes, there are tricks seasoned C++ veterans may use to decipher such horrors, but that’s not what this tip is about. This tip is about how you don’t need to remember this horrible syntax and still be able to declare such function pointer typedefs (e.g. in case you’re interacting with some legacy API that never heard of boost::function). Instead of breaking a mental sweat, let the compiler do the work for you. Next time you’re trying to create a typedef to a member function that looks like this:

struct C {
        const C& Callback(const C&) const   { }
};

Instead of struggling to manually come up with the complex syntax above, induce an intentional compilation error which will force the compiler to name the beast.

For example:

char c = &C::Callback;

The compiler happily spews this helpful error message:

“… cannot convert from 'const C &(__cdecl C::* )(const C &) const' to 'char'”

Which is what we’re looking for. :)

Upvotes: 55

Lucas
Lucas

Reputation: 14129

Nothing I actually came across while programming, but a friend wanted an explanation on why the code worked. It took me a while to figure it out. Maybe it is obvious to you guys, but I am not an experienced programmer.

#include <iostream>
using namespace std;

int& strangeFunction(int& x){return x;}


int main(){
        int a=0;
        strangeFunction(a) = 5;               //<------- I found this very confusing
        cout << a <<endl;
        return 0;
}

Upvotes: 1

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 506925

Sometimes, headers are polluted with not behaving macro names like

#define max(a, b) (a > b ? a : b)

Which will render code invalid that uses a max function or function object called that way. An infamous example is windows.h which does exactly that. One way around it is putting parentheses around the call, which stops it from using the macro and makes it use the real max function:

void myfunction() {
    ....
    (max)(c, d);
}

Now, the max is in parentheses and it is not counted as a call to the macro anymore!

Upvotes: 11

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 506925

I've liked this since the time i've discovered it in some code:

assert(condition || !"Something has gone wrong!");

or if you don't have a condition at hand, you can just do

assert(!"Something has gone wrong!");

The following is attributed to @Josh (see comments). It uses the comma operator instead:

assert(("Something has gone wrong!", condition)); 

Upvotes: 18

fizzer
fizzer

Reputation: 13796

Since we're all ignoring the OP and instead posting our favourite cool tricks...

Use boost (or tr1) shared_ptr to maintain a class invariant at runtime (kind of obvious, but I haven't seen anyone else do it):

#include <cassert>
#include <functional>
#include <stdexcept>
#include <boost/shared_ptr.hpp>
using namespace std;
using namespace boost;

class Foo
{
public:
    Foo() : even(0)
    {
        // Check on start up...
        Invariant();
    }

    void BrokenFunc()
    {
        // ...and on exit from public non-const member functions.
        // Any more is wasteful.
        shared_ptr<Foo> checker(this, mem_fun(&Foo::Invariant));

        even += 1;
        throw runtime_error("didn't expect this!");
        even += 1;
    }

private:
    void Invariant() { assert(even % 2 == 0); }
    int even;
};

Upvotes: 5

coppro
coppro

Reputation: 14516

You can often hide way more stuff in source files than you think. Don't make everything private if you don't have to - it's often better to leave it in an anonymous namespace in the source file. It actually makes things easier to process, I find, because then you aren't revealing implementation details, yet get inspired to make lots of tiny functions rather than monolithic ones.

Upvotes: 7

Ferruccio
Ferruccio

Reputation: 100648

Since I learned about RAII (one of the worst acronyms ever) and smart pointer, memory and resource leaks have almost completely disappeared.

Upvotes: 5

AntonioCS
AntonioCS

Reputation: 8496

I can't say that I am an experienced C++ programmer but I have recently learned how hard it is to pass and array of arrays as a function parameter. Try to avoid this at all cost :(

If you know the size at compile its simple. Even if you know one of the dimensions at compile time. If you simply don't know... you might be looking at something like this

m[i*dim2+j]

Being i the iterator for the rows, dim2 the number of cols and j the iterator for the cols.

Upvotes: 0

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247949

A few things that usually trip people up:

std::cout << a << a++ << --a;
i = ++i;

The above lines are both undefined.

void foo(bar* b1, bar* b2);

int main() {
  foo(shared_ptr<bar>(new bar()), shared_ptr<bar>(new bar()));
}

The above may leak memory.

int* arr = new int[10];
arr + 11;

This results in undefined behavior.

As for idioms, my favorite is RAII. Allocate objects on the stack, which guarantees that the destructor is called when the object goes out of scope, preventing resource leaks.

Upvotes: 5

Johannes Schaub - litb
Johannes Schaub - litb

Reputation: 506925

Here is another one i caught some day:

char int2hex(int x) {
     return "-0123456789abcdef"[(x >= 0 && x < 16) ? (x + 1) : 0];
}

it's just indexing the char array instead of doing a switch. If it's outside the range, it returns '-'.

Upvotes: 18

JaredPar
JaredPar

Reputation: 754665

If you have a class which does not have value semantics, make sure that all of the following constructs are explicitly declared in order to prevent headaches down the road.

  • Default Constructor
  • Copy Constructor
  • Assignment Operator

In many cases you only need to declare a subset of these constructs. However it can get really tricky in some cases as to which are needed and which are not. It's much safer to declare all 3 private and be done with the matter.

It's also very helpful to add a comment to the top explaining that this is not a copy safe class.

This will save you time down the road.

Upvotes: 3

Procedural Throwback
Procedural Throwback

Reputation: 360

One seldom used, but handy C++ idiom is the use of the ?: operator during the constructor chain.

class Sample
{  
    const char * ptr;
    const bool  freeable;

    Sample(const char * optional):
        ptr( optional ? optional : new char [32]),
        freeable( optional ? false : true ) {}
    ~Sample( )  { if (freeable) delete[] ptr; }
}  

C++ doesn't allow const values to be changed inside the body of the constructor, so this avoids const-casts.

Upvotes: 7

Luc Hermitte
Luc Hermitte

Reputation: 32926

Never waste time on trying to implement the copy operations on classes when we don't know if it will be required later. Many objects we handle are just entities, and copying them hardly make any sense. Make them non-copyable, and implement the copy/duplication later if the need really arises.

Upvotes: 14

Related Questions