मेह, मैंने आपके द्वारा दिए गए स्निपेट को चलाने की कोशिश की test.cpp
, gcc और क्लैंग और कई अनुकूलन स्तरों के माध्यम से:
steve@steve-pc /tmp> g++ -o test.gcc.O0 test.cpp
[ 0s828 | Jan 27 01:16PM ]
steve@steve-pc /tmp> g++ -o test.gcc.O2 -O2 test.cpp
[ 0s901 | Jan 27 01:16PM ]
steve@steve-pc /tmp> g++ -o test.gcc.Os -Os test.cpp
[ 0s875 | Jan 27 01:16PM ]
steve@steve-pc /tmp> ./test.gcc.O0
0 32764 [ 0s004 | Jan 27 01:16PM ]
steve@steve-pc /tmp> ./test.gcc.O2
0 0 [ 0s004 | Jan 27 01:16PM ]
steve@steve-pc /tmp> ./test.gcc.Os
0 0 [ 0s003 | Jan 27 01:16PM ]
steve@steve-pc /tmp> clang++ -o test.clang.O0 test.cpp
[ 1s089 | Jan 27 01:17PM ]
steve@steve-pc /tmp> clang++ -o test.clang.Os -Os test.cpp
[ 1s058 | Jan 27 01:17PM ]
steve@steve-pc /tmp> clang++ -o test.clang.O2 -O2 test.cpp
[ 1s109 | Jan 27 01:17PM ]
steve@steve-pc /tmp> ./test.clang.O0
0 274247888 [ 0s004 | Jan 27 01:17PM ]
steve@steve-pc /tmp> ./test.clang.Os
0 0 [ 0s004 | Jan 27 01:17PM ]
steve@steve-pc /tmp> ./test.clang.O2
0 0 [ 0s004 | Jan 27 01:17PM ]
steve@steve-pc /tmp> ./test.clang.O0
0 2127532240 [ 0s002 | Jan 27 01:18PM ]
steve@steve-pc /tmp> ./test.clang.O0
0 344211664 [ 0s004 | Jan 27 01:18PM ]
steve@steve-pc /tmp> ./test.clang.O0
0 1694408912 [ 0s004 | Jan 27 01:18PM ]
तो यह वह जगह है जहाँ यह दिलचस्प हो जाता है, यह स्पष्ट रूप से क्लेंग O0 बिल्ड दिखाता है यादृच्छिक संख्या पढ़ रहा है, संभवतः स्टैक स्पेस।
मैंने जल्दी से अपनी आईडीए को देखा कि क्या हो रहा है:
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
__int64 v4; // rax
int result; // eax
unsigned int v6; // [rsp+8h] [rbp-18h]
unsigned int v7; // [rsp+10h] [rbp-10h]
unsigned __int64 v8; // [rsp+18h] [rbp-8h]
v8 = __readfsqword(0x28u); // alloca of 0x28
v7 = 0; // this is foo a{}
bar::bar((bar *)&v6); // this is bar b{}
v3 = std::ostream::operator<<(&std::cout, v7); // this is clearly 0
v4 = std::operator<<<std::char_traits<char>>(v3, 32LL); // 32 = 0x20 = ' '
result = std::ostream::operator<<(v4, v6); // joined as cout << a.a << ' ' << b.b, so this is reading random values!!
if ( __readfsqword(0x28u) == v8 ) // stack align check
result = 0;
return result;
}
अब, क्या करता bar::bar(bar *this)
है?
void __fastcall bar::bar(bar *this)
{
;
}
हम्म, कुछ नहीं। हमें असेंबली का उपयोग करने का सहारा लेना पड़ा:
.text:00000000000011D0 ; __int64 __fastcall bar::bar(bar *__hidden this)
.text:00000000000011D0 public _ZN3barC2Ev
.text:00000000000011D0 _ZN3barC2Ev proc near ; CODE XREF: main+20↓p
.text:00000000000011D0
.text:00000000000011D0 var_8 = qword ptr -8
.text:00000000000011D0
.text:00000000000011D0 ; __unwind {
.text:00000000000011D0 55 push rbp
.text:00000000000011D1 48 89 E5 mov rbp, rsp
.text:00000000000011D4 48 89 7D F8 mov [rbp+var_8], rdi
.text:00000000000011D8 5D pop rbp
.text:00000000000011D9 C3 retn
.text:00000000000011D9 ; } // starts at 11D0
.text:00000000000011D9 _ZN3barC2Ev endp
तो हाँ, यह सिर्फ कुछ भी नहीं है, जो कि मूल रूप से कंस्ट्रक्टर करता है this = this
। लेकिन हम जानते हैं कि यह वास्तव में यादृच्छिक अनइंस्टाल्ड स्टैक एड्रेस लोड कर रहा है और इसे प्रिंट करता है।
क्या होगा यदि हम स्पष्ट रूप से दो संरचनाओं के लिए मूल्य प्रदान करते हैं?
#include <iostream>
struct foo {
foo() = default;
int a;
};
struct bar {
bar();
int b;
};
bar::bar() = default;
int main() {
foo a{0};
bar b{0};
std::cout << a.a << ' ' << b.b;
}
मारो क्लैंग, उफ़्पी:
steve@steve-pc /tmp> clang++ -o test.clang.O0 test.cpp
test.cpp:17:9: error: no matching constructor for initialization of 'bar'
bar b{0};
^~~~
test.cpp:8:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion
from 'int' to 'const bar' for 1st argument
struct bar {
^
test.cpp:8:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion
from 'int' to 'bar' for 1st argument
struct bar {
^
test.cpp:13:6: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
bar::bar() = default;
^
1 error generated.
[ 0s930 | Jan 27 01:35PM ]
जी ++ के साथ भी ऐसा ही भाग्य:
steve@steve-pc /tmp> g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:17:12: error: no matching function for call to ‘bar::bar(<brace-enclosed initializer list>)’
bar b{0};
^
test.cpp:8:8: note: candidate: ‘bar::bar()’
struct bar {
^~~
test.cpp:8:8: note: candidate expects 0 arguments, 1 provided
test.cpp:8:8: note: candidate: ‘constexpr bar::bar(const bar&)’
test.cpp:8:8: note: no known conversion for argument 1 from ‘int’ to ‘const bar&’
test.cpp:8:8: note: candidate: ‘constexpr bar::bar(bar&&)’
test.cpp:8:8: note: no known conversion for argument 1 from ‘int’ to ‘bar&&’
[ 0s718 | Jan 27 01:35PM ]
तो इसका मतलब यह है कि यह एक प्रत्यक्ष आरंभीकरण है bar b(0)
, न कि प्रारंभिक इनिशियलाइज़ेशन।
यह शायद इसलिए है क्योंकि यदि आप एक स्पष्ट निर्माण कार्यान्वयन प्रदान नहीं करते हैं तो यह संभवतः एक बाहरी प्रतीक हो सकता है, उदाहरण के लिए:
bar::bar() {
this.b = 1337; // whoa
}
कंपाइलर स्मार्ट नहीं है ताकि इसे गैर-अनुकूलित चरण में नो-ऑप / इनलाइन कॉल के रूप में घटाया जा सके।