Search code examples
c++volatileside-effects

Are 'volatile' and 'side effect' related?


Just a beginner question.

In the code from cppreference.com, there is a comment saying, "make sure it's a side effect" on the line using std::accumulate.

  1. What is the author's intention in saying this? Is it related to the volatile int sink? (Maybe it means something like "make sure the sink is not optimized by the compiler"?)

  2. Why volatile for sink? I think almost every compiler might know the std::accumulate will change the value of sink.

I thought I knew what volatile and "side-effect" meant, but maybe I'm missing some point!

#include <iostream>
#include <iomanip>
#include <vector>
#include <numeric>
#include <chrono>
 
volatile int sink;
int main()
{
    std::cout << std::fixed << std::setprecision(9) << std::left;
    for (auto size = 1ull; size < 1000'000'000ull; size *= 100) {
        // record start time
        auto start = std::chrono::system_clock::now();
        // do some work
        std::vector<int> v(size, 42);

        // This is the line I mentioned.
        sink = std::accumulate(v.begin(), v.end(), 0u); // make sure it's a side effect

        // record end time
        auto end = std::chrono::system_clock::now();
        std::chrono::duration<double> diff = end - start;
        std::cout << "Time to fill and iterate a vector of " << std::setw(9)
                  << size << " ints : " << diff.count() << " s\n";
    }
}

Solution

  • Not necessarily.

    C++ has the 'as if' rule. The compiler must generate code that works 'as if' the source code was executed, but it doesn't have to do everything that the source code does, in exactly the same order.

    Now look at the sink variable. After the line you mention it's never used again. So it's value has no visible effect on the program. So why should the compiler bother calculating it's value? Because of the as if rule it is perfectly legal for the compiler not to do so.

    But there are a few exceptions to the as if rule, and one of them is volatile variables. Reads and writes to volatile variables must occur in exactly the way that the source code says. That's why volatile is important in this code. It forces the compiler to execute the std::accumulate call even though it has no visible effect on the program.

    Further reading https://en.cppreference.com/w/cpp/language/as_if