2017-09-25 1 views
0

Umgebung: vs2013 RC5/vs2017;
Projekt: win32 Konsolenanwendung;ein überraschender Wert über Lambda und cin.get

Darstellung: kompilieren und eine Weile läuft, dann unterbrechen und Variable "task_" sehen;
wenn "add_task (& Test :: print, & t, str, 10)" in func main, der "task_" ist der richtige Wert;

aber wenn "add_task (& Test :: print, & t, str, 10)" in func mytest, der "task_" ist falscher Wert; und wenn ich std :: cin.get() durch while (1) {} ersetze, dreht es sich nach rechts;


#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

falschen Wert: Leere (void) {func = 0xa4509c83 self = 0x0f93c1b0 {msvcp120d.dll std :: basic_ostream > std :: cout} {. ..} ...} – fredirty2017

+0

korrekter Wert: void (void) {func = 0x00b51087 {tp_test.exe! Test :: print (Klasse std :: basic_string , Klasse std :: allocator > const &, int)} ...} – fredirty2017

Antwort

0

In C++ wird der Compiler nicht genau das tun erforderlich, was Sie denken es wäre, wenn es durch die Linie Ihre Codezeile ausführt. Es kann nach der "als-ob" -Regel optimiert werden, was bedeutet, dass es etwas anderes tun kann, das schneller wird, wenn das beobachtbare Verhalten dasselbe ist.

Observable Verhalten enthält nicht das Ausführen des Codes in einem Debugger.

Die Variable task_ hat für ein beobachtbares Verhalten niemals eine Konsequenz, daher kann ein entsprechender Compiler das Ganze optimieren. Die Funktion add_task wirkt sich nicht auf beobachtbares Verhalten aus, so dass ein konformer Compiler sie vollständig optimieren kann.

(Ich bin mir nicht sicher, ob es das tatsächlich hier tun würde, aber nur, weil std::function eine dynamische Zuordnung vornehmen muss, und wenn das passiert, wird es für den Compiler schwieriger, über beobachtbare Nebenwirkungen nachzudenken.)

Auch, da my_test keine Konsequenzen für irgendetwas hat, das durch std::cin.get() berührt wird, ist der Compiler frei, diese zwei Aussagen neu zu ordnen, wenn es denkt, dass es schneller gehen könnte.

Sie sollten Dinge tun, führen Sie die Funktion in test_ Variable, wenn Sie das Optimierungsprogramm zwingen, Dinge in einer bestimmten Reihenfolge zu tun, oder Commit auf bestimmte Speicherinhalte zu einem bestimmten Zeitpunkt.

0

thx Ihre Antwort. in Affekt, ich starte Debug-Version und schließe alles optimieren, es geschieht wie zuvor. in falschen Fall, ich einfügen task_() gerade vor dem std :: cin.get(), wird es abstürzen:

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 

so debuggen i, Breakpoint in task_(), drücken Sie F11 und Demontage, Absturz bei Datei "funktional":

_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