2017-09-25 7 views
0

環境cin.get:vs2013のRC5/vs2017;
プロジェクト:Win32コンソールアプリケーション、ラムダについての驚くべき値と

表現:少しの間をコンパイルして実行し、中断し、変数 "task_" を見ると、
func mainの "add_task(& Test :: print、& t、str、10)"の場合、 "task_"は正しい値です。

func mytestの "add_task(& Test :: print、& t、str、10)"の場合、 "task_"は間違った値です。 std :: cin.get()をwhile(1){}に置き換えると、右に変わります。 C++で


#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; 
} 
+0

誤った値:!無効(無効){FUNC = 0xa4509c83自己= 0x0f93c1b0 {msvcp120d.dllのstd :: basic_ostream <文字、のstd :: char_traits >のstd :: coutを} {。 ..} ...} – fredirty2017

+0

正しい値:void (void){func = 0x00b51087 {テスト用のprint(クラスstd :: basic_string 、クラスstd :: allocator > const&、int)} ...} – fredirty2017

答えて

0

それはラインであなたのコード行を実行した場合、コンパイラは、あなたはそれがだと思う正確に何をする必要はありません。 "as-if"ルールに従って最適化することができます。つまり、観察可能な振る舞いが同じ場合には、より速く進むことができることを意味します。

観察可能な動作には、デバッガでコードを実行することは含まれません。

変数task_は、観察可能な振る舞いにいかなる影響も与えないため、準拠しているコンパイラは完全に最適化することができます。関数add_taskは、観察可能な振る舞いには影響しないため、準拠しているコンパイラは完全に最適化するかもしれません。

(私が実際にここでそうするのかどうかはわかりませんが、std::functionは動的割り当てを行う必要があるかもしれませんが、それが起こるとコンパイラは観察可能な副作用を理由に考えるのが難しくなります)

また、は、std::cin.get()が触れたものに影響を与えませんので、コンパイラはこれらの2つの文を自由に並べ替えることができます。

変数をtest_のように実行し、オプティマイザが特定の順序で処理を実行するようにするか、特定の時間に特定のメモリ内容にコミットする必要があります。

0

あなたの答え。 が影響して、私はデバッグバージョンを実行し、すべての最適化を閉じると、beforとして発生します。間違った場合 、私は(task_を挿入する)だけではstd befor :: cin.get()、それがクラッシュします:

cccccccc() Unknown 
    [Frames below may be incorrect and/or missing] 
> tp_test.exe!add_task::__l3::<lambda>() Line 21 C++ 
    tp_test.exe!std::_Callable_obj<void <lambda>(void),0>::_ApplyX<void>() Line 284 C++ 
    tp_test.exe!std::_Func_impl<std::_Callable_obj<void <lambda>(void),0>,std::allocator<std::_Func_class<void> >,void>::_Do_call() Line 229 C++ 
    tp_test.exe!std::_Func_class<void>::operator()() Line 315 C++ 
    tp_test.exe!main() Line 39 C++ 
    tp_test.exe!__tmainCRTStartup() Line 626 C 
    tp_test.exe!mainCRTStartup() Line 466 C 
    kernel32.dll!765c8744() Unknown 
    ntdll.dll!__RtlUserThreadStart() Unknown 
    [email protected]() Unknown 

をので、私は、task_にブレークポイント()、F11キーを押し、分解、ファイルのクラッシュをデバッグ"機能":

_Ret operator()(_Types... _Args) const 
     { // call through stored object 
00BE36A0 push  ebp 
00BE36A1 mov   ebp,esp 
00BE36A3 sub   esp,0CCh 
00BE36A9 push  ebx 
00BE36AA push  esi 
00BE36AB push  edi 
00BE36AC push  ecx 
00BE36AD lea   edi,[ebp-0CCh] 
00BE36B3 mov   ecx,33h 
00BE36B8 mov   eax,0CCCCCCCCh 
00BE36BD rep stos dword ptr es:[edi] 
00BE36BF pop   ecx  <==========crash 
00BE36C0 mov   dword ptr [this],ecx