Guess Person *ptr=nullptr; ptr->dowork(); Will the program collapse?

Posted by stormcloud on Fri, 29 Oct 2021 13:39:28 +0200

At work today, I wrote the code happily.
A colleague ran over excitedly and said, "ah yuan, look at your enterprise wechat.".
Me: "what's the situation? Do you want a raise?"
Colleague: "will salary increase be said on enterprise wechat?"
Me: "Okay"
When I opened enterprise wechat, it turned out to be an interview question, -# - #.

#include <iostream>
using namespace std;
class Persion{
public:
	void doWork(){
		cout<<"Do you think I'll collapse?"<<endl;
	}
};
int main(){
	Persion *ptr =nullptr;
	ptr->doWork();	// Will the execution run out here? Guess, guess, guess again?
	return 0;
}

My first intuition: it's bound to collapse. It's all empty pointers. How can it not collapse, but you're good! You're fine!! Will my colleagues ask me such a simple question?
I replied solemnly, "no!!".
Colleague: "do you know why?"
My heart: ten thousand divine beasts are jumping!, Why do men bother men?

"Well, well... I still have a lot to do. You can play."
Finally fooled my colleagues away. Baidu immediately, I see.

Principle analysis

First, we need to know whether the function of a class belongs to a class or an object. The function of class belongs to class, that is, it is a fixed address, rather than dynamically generating a new address every time.

g++ -g test.cpp -o test #Compile debug mode
gdb test # gdb debugging

The source code is as follows:

Break the point and run the diagram

disassemble

You can see whether the function he calls is person:: dowork(), which is very similar to the static function call.
The main function, assembly code analysis and summary class function call actually has a hidden parameter, which is the this pointer.

Dump of assembler code for function main():
push   %rbp
mov    %rsp,%rbp
sub    $0x10,%rsp
movq   $0x0,-0x8(%rbp) # The assignment pointer is null.
mov    -0x8(%rbp),%rax # The beginning of the calling function. Use register rax to save the pointer address----- Start-----
mov    %rax,%rdi	   # rdi register is used to save function parameters. In fact, it is to pass this pointer to the function as a function parameter.	
callq  0x4011e8 <Persion::doWork()> # Call function 	 			------   End-----
mov    $0x0,%eax	 #  return 0
leaveq 
retq   
End of assembler dump.

note: the rdi register is used to hold parameters

dowork(), assembly code analysis, we can see that there is no assignment to rax in dowork, so there is no problem.

Dump of assembler code for function Persion::doWork():
   0x00000000004011e8 <+0>:     push   %rbp
   0x00000000004011e9 <+1>:     mov    %rsp,%rbp
   0x00000000004011ec <+4>:     sub    $0x10,%rsp
   0x00000000004011f0 <+8>:     mov    %rdi,-0x8(%rbp)
=> 0x00000000004011f4 <+12>:    mov    $0x402005,%esi
   0x00000000004011f9 <+17>:    mov    $0x404060,%edi
   0x00000000004011fe <+22>:    callq  0x401050 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
   0x0000000000401203 <+27>:    mov    $0x401030,%esi
   0x0000000000401208 <+32>:    mov    %rax,%rdi
   0x000000000040120b <+35>:    callq  0x401060 <_ZNSolsEPFRSoS_E@plt>
   0x0000000000401210 <+40>:    nop
   0x0000000000401211 <+41>:    leaveq 
   0x0000000000401212 <+42>:    retq   
End of assembler dump.

Run down test

If you change the code to:

#include <iostream>
using namespace std;
class Persion{
public:
	int a = 0;
	void doWork(){
		cout<<"Do you think I'll collapse?"<<endl;
	}
};
int main(){
	Persion *ptr =nullptr;
	ptr->doWork();	// Will the execution run out here? Guess, guess, guess again?
	ptr->a = 10;
	return 0;
}

When using the pointer PTR - > A, it will crash because the null pointer cannot get the address.

summary

Do you think the people who answer this interview question eat too many walnuts pinched by the door? In fact, this problem occurred in my real project. A novice really didn't have new when using the pointer. Due to the logic problem, his this pointer will be called in a specific situation. It also took a lot of time to find the problem, and finally found the reason.

  1. Class hides the passing of a this pointer.
  2. Class is used to hold the variables of the object.
  3. The function of a class belongs to a class, not an object, that is, each object uses the same function.

Ha ha, did you learn??

Topics: C++