3

The standard arithmetic operators, such as * and +, work as expected on classes like atomic< int >. However, I can't find any definition of them in the <atomic> header file and no reference to them in the standard.

Are they defined implicitly somewhere or am I just looking in the wrong place?

For example, where is the multiplication function called in the following code defined?

#include <iostream>
#include <atomic>
using namespace std;

int main() {

    atomic< int > i( 42 );
    atomic< float > f( 6.66 );

    cout << i * f;
    //cout << operator*( i, f); //error: ‘operator*’ not defined

    return 0;
}

For anyone else reading this question there is a nice discussion of what is going on here.

Community
  • 1
  • 1
andypea
  • 1,343
  • 11
  • 22

2 Answers2

2

The atomic types have a conversion operator T that reads atomically - in your i * f expression they're both read atomically, thereafter the extracted values - held in CPU registers - are of plain int and float types and multiplied as per any other pair of int and float, with the result provided to operator<<'s float overload.

Keep in mind that the whole idea of atomicity is about loading and storing values from memory in such a way that readers don't see half-written values, and writers don't overlap leaving some hybrid of two values in memory. Once an atomic value is loaded into a register for some actual use in an expression, or say as a function parameter, it's not accessible to other threads or updated by their writes to the original atomic variable.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • Thanks, I'd never come across these `operator T()` functions before. Do they have a technical name? I'd like to look them up in the standard. – andypea Feb 13 '14 at 05:30
  • 1
    @andrew.punnett You're welcome. You want "conversion functions" - see 12.3 and 12.3.2. Cheers. – Tony Delroy Feb 13 '14 at 05:35
  • Thanks, I guess they very similar to an overloaded C-style cast function. – andypea Feb 13 '14 at 05:37
  • 1
    @andrew.punnett: they're closely related concepts, albeit kind of the other end of the process... this grants the ability to cast from a custom object *to* a specific type, while if you did a C-style cast the the casted-to type would need a constructor *from* this type, which is never possible for a builtin-type. That is, a user-defined type can't be cast to e.g. `double` unless it provides an `operator double()` or e.g. `operator T` for some type `T` that can undergo a Standard Conversion to `double`. – Tony Delroy Feb 13 '14 at 06:26
1

atomic<T> provides operator T(). Then built-in operators are happily applied to underlying fundamental types.

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85