2013 10 08_cpp_lecture_05
description
Transcript of 2013 10 08_cpp_lecture_05
Лекция 5. Функции
С++ Basics. Valery Lesin 2013 1
Стуктурное программирование
• Три базовых конструкции 1. Последовательное исполнение
2. Ветвление
3. Циклы
• Повторяющийся код -> подпрограммы
• Пошаговая древовидная разработка «сверху вниз».
• Теорема Бёма-Якопини: любой алгоритм можно представить в виде описанных базовых конструкций
• Не используйте GOTO (Дейкстра бы не одобрил)
С++ Basics. Valery Lesin 2013 2
Объявление функций
1. [спецификатор] <возвр. тип> имя([<аргументы>]){ /*тело*/ }
С++ Basics. Valery Lesin 2013 3
• Формальные аргументы находятся в самой
внешней области видимости функции.
• Локальные переменные по умолчанию
инициализируется мусором.
• Объявляйте их поближе к месту использования.
• Статические локальные переменные
инициализируются при первом «выполнении»
определения. Живут до конца программы.
Передача параметров
• Варианты: по значению, указателю/ссылке
• Input:
– Базовые (int, double) и маленькие (complex, point) типы – по значению
– Остальные объекты – константные ссылки
– Нужна внутри копия – хорошо передать по значению
• Ouput (or mix):
– Необязательный параметр – по указателю (умному). Можно передать 0.
– Обязательный – лучше по неконстантной ссылке.
С++ Basics. Valery Lesin 2013 4
Передача параметров. Примеры
• При вызове выполняется проверка и преобразование типов а-ля инициализация (одношаговая).
С++ 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);
Передача массивов
• Теряется размер. В случае 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);
Возврат значения
• Значение возвращается return. Вернуть
значение можно из любой точки функции.
• Можно вернуть и void. (Зачем?)
С++ Basics. Valery Lesin 2013 7
1.
2.
void foo(){}
void bar(){ return foo(); }
• При возвращении происходит инициализация
временной переменной возвращаемого типа.
• Не возвращайте ссылки/указатели на
локальные переменные.
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()
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);
Перегрузка. Выбор функции
• Порядок выбора перегрузки:
1. Полное соответствие или тривиальное преобразование (T -> const T)
2. «Продвижение типа» без потерь: int -> long, float -> double
3. Стандартные преобразования (возможно, с потерей):
double -> int
4. Пользовательское преобразование
5. Соответствие за счет … (часть синтаксиса)
• Контекстно-независимо: возвращаемое значение не участвует в выборе.
• Много аргументов: один лучше, остальные не хуже.
• NB Сложно? А ведь есть еще шаблонные функции!
С++ Basics. Valery Lesin 2013 10
Перегрузка. Примеры
С++ 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;
}
Аргументы по умолчанию
• Описывает в объявлении, нельзя изменить в определении. (Почему?)
• По умолчанию могут быть только последние аргументы функции
С++ 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;
}
Произвольное количество аргументов
• Теряется знание о типе
С++ 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);
Указатель на функцию
С++ 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);
И снова определения 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;
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);
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;
}
Calling conventions*
• Определяет:
– Как передаются параметры (на стеке/через
регистры), как возвращается значение
– Порядок передачи параметров
– Кто чистит стек-фрейм
(вызывающий/вызываемый)
– Декорирование имени функции (для линковки)
– Какие регистры допускается изменять
С++ Basics. Valery Lesin 2013 18
cdecl, stdcall
• сdecl –конвенция в С++ по умолчанию
– Передача параметров RTL
– Очистка стека со стороны вызывающей функции -можно делать printf(…)
– Возврат через EAX или ST0
– Именование: _sum
• stdcall – стандартная для WinAPI
– Очистка стека со стороны вызываемой функции (меньше кода), нельзя делать printf(…)
– Именование: _sum@8
С++ Basics. Valery Lesin 2013 19
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
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
Вопросы?
С++ Basics. Valery Lesin 2013 22