atomic increment and return counter

A mutex is overkill.

There is no pre-increment atomic operation (but you can return the previous value and add one to that, of course).

As pointed out by Pete, your first code block attempts to do a pre-increment (return the result of the increment).

Doing return ++id works, but is equivalent to return id.fetch_add(1) + 1; which uses the slow default sequentially-consistent memory order. This is not required here, in fact you can do with a relaxed memory order.

If you really mean to use a global variable for the atomic, the correct (and fastest) code that does what your first code block attempts is:

int create_id() {
    static std::atomic<int> id{0};
    return id.fetch_add(1, std::memory_order_relaxed) + 1;
}

Notes:

You can leave away the + 1 if you want post-increment.

Using std::memory_relaxed doesn't make a difference on Intel CPU's (x86) because fetch_add is a Read-Modify-Write operation and the bus must be locked anyway (lock assembly instruction). But on a more relaxed architecture it does make a difference.

I didn't want to pollute global namespace with 'id', so I put it as a static in the function; however in that case you must make sure that on your platform that doesn't lead to actual initialization code. E.g. if a constructor that isn't constexpr needs to be called then a test is necessary to see if the static was already initialized or not. Fortunately, the value initializing constructor of an integral atomic is constexpr, so the above leads to constant initialization.

Otherwise you'd want to make it -say- a static member of a class that is wrapping this and put the initialization somewhere else.


Simply use:

std::atomic<int> id{};

int create_id() {
    return id++;
}

See http://en.cppreference.com/w/cpp/atomic/atomic/operator_arith


Your two code snippets do two different things.

id++;
return id.load();

that code increments id, then returns the incremented value.

std::lock_guard<std::mutex> lock{mx};
return id++;

that code returns the value before the increment.

The correct code to do what the first tries to do is

return ++id;

The correct code to do what the second does is

return id++;