environment: vs2013 rc5 / vs2017;
project: win32 console application;
representation:compile and run a little while,then interrupt and watch variable "task_";
if "add_task(&Test::print, &t, str, 10)" in func main, the "task_" is correct value;
but if "add_task(&Test::print, &t, str, 10)" in func mytest, the "task_" is wrong value; and if replace std::cin.get() with while(1){}, it turns right;
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <functional>
using task_t = std::function<void()>;
class Test
{
public:
void print(const std::string& str, int i)
{
std::cout << "Test: " << str << ", i: " << i << std::endl;
}
};
template<typename Function, typename Self, typename... Args>
void add_task(const Function& func, Self* self, Args... args)
{
task_t task = [&func, &self, args...]{ return (*self.*func)(args...); };
task_ = task;
}
Test t;
std::string str = "Hello world";
task_t task_ = nullptr;
void mytest()
{
add_task(&Test::print, &t, str, 10);
}
int main()
{
mytest();
std::cin.get();
return 0;
}
In C++, the compiler is not required to do exactly what you think it would if it executes your code line by line. It may optimize according to the "as-if" rule, meaning that it can do something else that will go faster if the observable behavior is the same.
Observable behavior does not include running the code in a debugger.
The variable
task_never has any consequence for any observable behavior, so a conforming compiler may optimize it out entirely. The functionadd_taskdoesn't affect any observable behavior, so a conforming compiler may optimize it out entirely.(I'm not sure if it would actually do so here, but only because
std::functionmay have to make a dynamic allocation, and when that happens it becomes harder for the compiler to reason about observable side-effects.)Also, since
my_testdoes not have any consequences for anything touched bystd::cin.get(), the compiler is free to reorder these two statements if it think it might go faster.You should do things like, run the function in
test_variable, if you want to force the optimizer to do things in a particular order, or commit to particular memory contents at a particular time.