?

Log in

No account? Create an account
Юному программисту: Вопрос на засыпку - Коммик, Just Коммик — LiveJournal
July 11th, 2019
12:36 pm

[Link]

Previous Entry Share Next Entry
Юному программисту: Вопрос на засыпку
Что произойдет при исполнении этой программы на C++ и почему?

File test4.cpp:
=======================================
#include 

class Foo {
public:
	void f() {
		std::cout << "Let's begin!" << std::endl;
		x += 1;                                  // Line 7
		std::cout << x;
	}

	int x = 0;
};

int main () {
	Foo *bar = nullptr;
	// Now we will try to dereference a null pointer:
	bar->f();                                      // Line 17
	return 0;
}

========================================

Подсказка:
Console:
Let's begin!

Stack trace:
Thread #1 unnamed (STOPPED) (Suspended : Signal : SIGSEGV:Segmentation fault) 
Foo::f() at test4.cpp:7 0x100c94cc 
main() at test4.cpp:17 0x100c9434


Хороший вопрос для выявления матерого программиста на интервью.

Как вы думаете, каков будет процент правильных ответов?

Tags: ,

(5 comments | Leave a comment)

Comments
 
[User Picture]
From:calcin
Date:July 11th, 2019 08:00 pm (UTC)
(Link)
Матерого? По-моему, только на джуна.
То, что не-виртуальную функцию класса можно вызвать по нулевому this, и она отработает нормально до тех пор, пока не попытается обратиться к переменным класса или виртуальным функциям - в общем, не является чем-то секретным или сложным.
[User Picture]
From:stalinist
Date:July 11th, 2019 08:44 pm (UTC)
(Link)
Но это является странным. Почему компилятор разрешает исполнять функцию, не проверив сначала this, чтобы дать SIGSEGV в точке вызова функции, а не внутри её? Это создаёт очень тяжелое впечатление при отладке, когда происходит crash в месте, где его, кажется, никогда не может быть.

Edited at 2019-07-11 08:46 pm (UTC)
[User Picture]
From:calcin
Date:July 12th, 2019 06:57 am (UTC)
(Link)
Ну, во-первых, компилятор этого проверить не может. Эту проверку надо делать в runtime.

А во-вторых - производительность. Если всегда проверять this при входе в функцию-член класса, то тривиальные функции будут работать отчётливо дольше.

Изначально С и С++ строились как быстрые языки, с минимальными проверками, практически напрямую транслируемыми в ассемблер.

Кстати, проверять на null недостаточно - для нормальной проверки надо использовать динамический контроль типов, так как может быть и ненулевой указатель, указывающий на левый адрес в памяти.

Крупные классовые библиотеки, типа Qt например, стараются в функциях напихать побольше assert-ов, в том числе - и для this.
[User Picture]
From:stalinist
Date:July 12th, 2019 12:20 pm (UTC)
(Link)
Спасибо, товарищ, очень поучительно! По правде говоря, я потерял пару дней на расследовании подобной проблемы, когда она изредка появлялась в течении 36-часового автоматического тестирования.
[User Picture]
From:stalinist
Date:July 12th, 2019 03:45 pm (UTC)

Вдохновленный вами улучшенный вариант

(Link)
#include 
#include <аssert.h>

class Foo {
public:
    void f() {
        std::cout << "this = " << this << std::endl;
        аssert(this);
        x += 1;
        std::cout << x;
    }

    int x = 0;
};

int main () {
    Foo *bar = nullptr;
    // Now we will try to dereference a null pointer:
    bar->f();
    return 0;
}

Console:
this = 0
In function f -- src/test4.cpp:8 this -- assertion failed

Stack trace:
Thread #1 unnamed (STOPPED) (Suspended : Signal : SIGABRT:Aborted)	
	SignalKill() at 0x104ece0	
	abort() at 0x10395ec	
	__assert() at 0x103c7ac	
	Foo::f() at test4.cpp:8 0x100c95c0	
	main() at test4.cpp:19 0x100c94f4	


Edited at 2019-07-12 03:47 pm (UTC)
Powered by LiveJournal.com