2013 10 08_cpp_lecture_05

22
Лекция 5. Функции С++ Basics. Valery Lesin 2013 1

description

 

Transcript of 2013 10 08_cpp_lecture_05

Page 1: 2013 10 08_cpp_lecture_05

Лекция 5. Функции

С++ Basics. Valery Lesin 2013 1

Page 2: 2013 10 08_cpp_lecture_05

Стуктурное программирование

• Три базовых конструкции 1. Последовательное исполнение

2. Ветвление

3. Циклы

• Повторяющийся код -> подпрограммы

• Пошаговая древовидная разработка «сверху вниз».

• Теорема Бёма-Якопини: любой алгоритм можно представить в виде описанных базовых конструкций

• Не используйте GOTO (Дейкстра бы не одобрил)

С++ Basics. Valery Lesin 2013 2

Page 3: 2013 10 08_cpp_lecture_05

Объявление функций

1. [спецификатор] <возвр. тип> имя([<аргументы>]){ /*тело*/ }

С++ Basics. Valery Lesin 2013 3

• Формальные аргументы находятся в самой

внешней области видимости функции.

• Локальные переменные по умолчанию

инициализируется мусором.

• Объявляйте их поближе к месту использования.

• Статические локальные переменные

инициализируются при первом «выполнении»

определения. Живут до конца программы.

Page 4: 2013 10 08_cpp_lecture_05

Передача параметров

• Варианты: по значению, указателю/ссылке

• Input:

– Базовые (int, double) и маленькие (complex, point) типы – по значению

– Остальные объекты – константные ссылки

– Нужна внутри копия – хорошо передать по значению

• Ouput (or mix):

– Необязательный параметр – по указателю (умному). Можно передать 0.

– Обязательный – лучше по неконстантной ссылке.

С++ Basics. Valery Lesin 2013 4

Page 5: 2013 10 08_cpp_lecture_05

Передача параметров. Примеры

• При вызове выполняется проверка и преобразование типов а-ля инициализация (одношаговая).

С++ Basics. Valery Lesin 2013 5

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

struct X {};

struct Y { Y(){} Y(X){} };

struct Z { Z(){} Z(Y){} };

void apply(Z){}

int main()

{

apply(Y()); // ok, just one-step conversion

apply(X()); // wrong

}

• Порядок вычисления аргументов не определен.

1.

2.

void foo(int a, int& b, int){/*...*/}

foo(++i, arr[i + 1], 0);

Page 6: 2013 10 08_cpp_lecture_05

Передача массивов

• Теряется размер. В случае C-строки не так страшно.

• Массив преобразуется в указатель (T[] -> T*)

С++ Basics. Valery Lesin 2013 6

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

void sort(float* arr, size_t size);

void sort(std::vector<float>& arr);

//...

const size_t size = 256;

float a[size];

sort(a, size);

std::vector<float> b;

sort(b);

Page 7: 2013 10 08_cpp_lecture_05

Возврат значения

• Значение возвращается return. Вернуть

значение можно из любой точки функции.

• Можно вернуть и void. (Зачем?)

С++ Basics. Valery Lesin 2013 7

1.

2.

void foo(){}

void bar(){ return foo(); }

• При возвращении происходит инициализация

временной переменной возвращаемого типа.

• Не возвращайте ссылки/указатели на

локальные переменные.

Page 8: 2013 10 08_cpp_lecture_05

Return Value Optimization (RVO)

• В зависимости от компилятора и настроек

С++ Basics. Valery Lesin 2013 8

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

struct C

{

C() { cout << "C()";}

C(const C&) { cout << "C(C const&)"; }

};

C f() { return C(); }

int main()

{

C obj = f();

return 0;

}

1.

2.

3.

C()

C(C const&)

C(C const&)

1.

2.

3.

C()

C(C const&) 1.

2.

3.

C()

Page 9: 2013 10 08_cpp_lecture_05

R-value reference* (C++11)

С++ Basics. Valery Lesin 2013 9

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

18.

vector<int> make_indices(vector<int>&& non_opt)

{

vector<int> x = move(non_opt);

vector<int> y = /*...*/;

return (/*...*/) ? x : y;

}

int main()

{

vector<int> non_optimized;

vector<int> ind = make_indices(std::move(non_optimized));

return 0;

}

//...

vector& operator=(vector&& other);

Page 10: 2013 10 08_cpp_lecture_05

Перегрузка. Выбор функции

• Порядок выбора перегрузки:

1. Полное соответствие или тривиальное преобразование (T -> const T)

2. «Продвижение типа» без потерь: int -> long, float -> double

3. Стандартные преобразования (возможно, с потерей):

double -> int

4. Пользовательское преобразование

5. Соответствие за счет … (часть синтаксиса)

• Контекстно-независимо: возвращаемое значение не участвует в выборе.

• Много аргументов: один лучше, остальные не хуже.

• NB Сложно? А ведь есть еще шаблонные функции!

С++ Basics. Valery Lesin 2013 10

Page 11: 2013 10 08_cpp_lecture_05

Перегрузка. Примеры

С++ Basics. Valery Lesin 2013 11

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

bool do_smth(int); // (1)

int do_smth(const char*); // (2)

int main()

{

do_smth(5); //(1)

do_smth("hello"); //(2)

do_smth(2.71); //(1)

do_smth(static_cast<const char*>(0)); // (2)

int cond = do_smth(0); // (1)

return 0;

}

Page 12: 2013 10 08_cpp_lecture_05

Аргументы по умолчанию

• Описывает в объявлении, нельзя изменить в определении. (Почему?)

• По умолчанию могут быть только последние аргументы функции

С++ Basics. Valery Lesin 2013 12

1.

2.

3.

4.

5.

6.

7.

8.

9.

string int_to_str(int value, int base = 10);

int main()

{

string s = int_to_str(15); // "15"

string h = int_to_str(33, 16); // "21"

return 0;

}

Page 13: 2013 10 08_cpp_lecture_05

Произвольное количество аргументов

• Теряется знание о типе

С++ Basics. Valery Lesin 2013 13

1.

2.

3.

4.

5.

6.

printf("name: %s; score: %.2lf\n", name.c_str(), score);

cout << "name: " << name << "; score: "

<< std::setprecision(3) << score << endl;

cout << (boost::format("name: %s; score: %.2lf\n") % name % score);

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

void log(size_t level, ...)

{

va_list list;

va_start(list, level);

for(const char* str = va_arg(list, const char*);

str != 0;

str = va_arg(list, const char*))

{

cout << str;

}

va_end(list);

}

log(1, "hello ", "world", (const char*)0);

Page 14: 2013 10 08_cpp_lecture_05

Указатель на функцию

С++ Basics. Valery Lesin 2013 14

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

18.

void foo(int x ){}

void foo(double y){}

//...

void (*bar)(int) = &foo;

void (*bad)(float) = &foo; //wrong

bar (5);

(*bar)(5);

//------------------------------------

typedef void(*log_writer)(int, string);

void add_writer(log_writer lw);

void console_writer(int, string);

//...

add_writer(console_writer);

Page 15: 2013 10 08_cpp_lecture_05

И снова определения auto

• Можно выводить тип по типу выражения

С++ Basics. Valery Lesin 2013 15

1.

2.

3.

4.

5.

6.

7.

8.

int x = 5;

auto y = 6;

std::map<int, string> m;

// std::map<int, string>::iterator

auto it = m.find(42);

auto& value = m[42];

• И упрощать определение member-функций*1.

2.

3.

4.

5.

6.

7.

8.

struct my_class

{

typedef my_class* pointer_t;

pointer_t get() const;

};

// my_class::pointer_t my_class::get() const;

auto my_class::get() const ->pointer_t;

Page 16: 2013 10 08_cpp_lecture_05

Anonymous functions (C++11)

С++ Basics. Valery Lesin 2013 16

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

// lambda functions

[capture](params) [-> return-type] {body}

// samples

[] (int x) { return x + global_y; }

[] (int x) -> int

{ z = x + global_y; return z; }

// capture type

[x, &y](){} // capture x by value, y by ref

[=, &x](){} // capture everything by value, x by ref

// more samples

matrix m;

auto rot = [&m](point& p){ p *= m; }

for_each(points.begin(), points.end(), rot);

Page 17: 2013 10 08_cpp_lecture_05

bind & function*

С++ Basics. Valery Lesin 2013 17

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

18.

19.

20.

21.

22.

using namespace std;

using namespace std::placeholders;

typedef std::function<void(int, string)> log_writer;

void add_writer(log_writer const& lw);

struct net_writer

{

void write(int level, string host, string app, string msg);

};

int main()

{

net_writer nw;

add_writer(bind(&net_writer::write,

&nw, _1, "192.168.0.1", "model", _2));

add_writer([&nw](int level, string msg)

{nw.write(level, "192.168.0.1", "model", msg);});

return 0;

}

Page 18: 2013 10 08_cpp_lecture_05

Calling conventions*

• Определяет:

– Как передаются параметры (на стеке/через

регистры), как возвращается значение

– Порядок передачи параметров

– Кто чистит стек-фрейм

(вызывающий/вызываемый)

– Декорирование имени функции (для линковки)

– Какие регистры допускается изменять

С++ Basics. Valery Lesin 2013 18

Page 19: 2013 10 08_cpp_lecture_05

cdecl, stdcall

• сdecl –конвенция в С++ по умолчанию

– Передача параметров RTL

– Очистка стека со стороны вызывающей функции -можно делать printf(…)

– Возврат через EAX или ST0

– Именование: _sum

• stdcall – стандартная для WinAPI

– Очистка стека со стороны вызываемой функции (меньше кода), нельзя делать printf(…)

– Именование: _sum@8

С++ Basics. Valery Lesin 2013 19

Page 20: 2013 10 08_cpp_lecture_05

Stack frame, cdecl Caller*

С++ Basics. Valery Lesin 2013 20

1.

2.

3.

4.

5.

6.

7.

int __cdecl sum(int a, int b)

{

return a + b;

}

int c = sum(2, 3);

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

// -- Caller

// push arguments to the stack, from right to left

push 3

push 2

// call the function

call _sum

// cleanup the stack by adding the size

// of the arguments to ESP register

add esp,8

// copy the return value from EAX to a local variable (int c)

mov dword ptr [c],eax

Page 21: 2013 10 08_cpp_lecture_05

Stack frame, cdecl Callee*

С++ Basics. Valery Lesin 2013 21

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

// function prolog

push ebp

mov ebp,esp

//...

// return a + b;

mov eax,dword ptr [a]

add eax,dword ptr [b]

// function epilog

//...

mov esp,ebp

pop ebp

ret

// ret 8 in case of stdcall

Page 22: 2013 10 08_cpp_lecture_05

Вопросы?

С++ Basics. Valery Lesin 2013 22