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
.
What is the author's intention in saying this? Is it related to the
volatile int sink
? (Maybe it means something like "make sure thesink
is not optimized by the compiler"?)Why
volatile
forsink
? I think almost every compiler might know thestd::accumulate
will change the value ofsink
.
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";
}
}
CodePudding user response:
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
CodePudding user response:
The issue in the code sample given is that the value of sink
is never used after it has been calculated. Thus, a compiler would be free to "optimize out" the call to std::accumulate
, as doing so would have no observable effect.
Adding the volatile
qualifier to sink
prevents such an undesired optimization. From another cppreference page (bold emphasis mine):
volatile object - An object whose type is volatile-qualified, or a subobject of a volatile object, or a mutable subobject of a const-volatile object. Every access (read or write operation, member function call, etc.) made through a glvalue expression of volatile-qualified type is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access. …)
CodePudding user response:
The example code referenced is intended to show timing functions. The C standard allows the compiler to look at some code, and remove it, if it believes the result is not used.
The example uses volatile
and the side effect to be sure that the timing is not optimized away by the compiler.