├── drafts ├── images └── build.md ├── examples_gdb ├── expr.txt ├── calc.cpp └── calc_fixed.cpp ├── images ├── cpp.png ├── gcc.png ├── llvm.png └── osx.png ├── examples ├── .vscode │ └── settings.json ├── lecture2 │ ├── 032_static_inline_second.c │ ├── 032_static_inline.h │ ├── 032_static_inline_main.c │ ├── 005_fork_bomb.c │ ├── 007_exec.c │ ├── 004_fork_basic.c │ ├── Makefile │ ├── 012_named_fifo_reader.c │ ├── 023_c11_atomic.c │ ├── 030___builtin_expect.c │ ├── 031_inline_functions.c │ ├── 027_packing_structs.c │ ├── 012_named_fifo_writer.c │ ├── 013_alarm.c │ ├── 011_popen.c │ ├── 024_c11_cas.c │ ├── 026_posix_memalign.c │ ├── 006_simple_waitpid.c │ ├── 003_file_io.c │ ├── 009_mmap_shared_memory.c │ ├── 016_mutex.c │ ├── 021_semaphore.c │ ├── 008_mmaped_file.c │ ├── 015_thread_routine.c │ ├── 025_aligned.c │ ├── 010_pipe.c │ ├── 028_matrix_sums_by_columns.c │ ├── 001_getopt.c │ ├── 029_matrix_mul.c │ ├── 002_getopt_long.c │ ├── 021_simple_cond_variables.c │ ├── 020_mutex_trylock_bench.c │ ├── 014_messages_queue.c │ ├── 017_lock_mutex_deadlock.c │ ├── 022_watcher_cond_variables.c │ ├── 019_trylock_mutex_without_deadlock.c │ └── 018_lock_mutex_without_deadlock.c ├── lecture1 │ ├── 014_reading_to_static_buffer.c │ ├── 017_double_prefix_operators.c │ ├── 001_memory_classes_1.h │ ├── 019_redundant_specifiers.c │ ├── Makefile │ ├── 020_different_enum_types_comparison.c │ ├── 002_address_of_register_variable.c │ ├── 001_memory_classes.c │ ├── 012_buffer_overflow.c │ ├── 022_continue.c │ ├── 021_nonnull_pointers.c │ ├── 001_memory_classes_1.c │ ├── 008_const_qualifier.c │ ├── 018_dead_stores.c │ ├── 004_static_arrays_initialization.c │ ├── 016_wrong_pointers_operations.c │ ├── 010_restrict_and_volatile_pointers.c │ ├── 013_insecure_count_limit.c │ ├── 015_double_free.c │ ├── 011_c11_generics.c │ ├── 009_arrays_as_function_arguments.c │ ├── 007_two_dimensional_array_vs_vector_of_vectors.c │ ├── 006_two_dimensional_arrays.c │ ├── 005_dynamic_memory_management.c │ └── 003_size_t_and_ptrdiff_t_types.c ├── lecture3 │ ├── Makefile │ ├── 023_noexcept_destructor.cpp │ ├── 019_delete_and_default_methods.cpp │ ├── 004_default_contructor.cpp │ ├── 003_initialization_without_constructor.cpp │ ├── 022_undefined_sizeof.cpp │ ├── 017_defaults_constructors.cpp │ ├── 018_trivial_constructors.cpp │ ├── 024_using_conflicts.cpp │ ├── 005_required_default_constructor_for_array.cpp │ ├── 012_placement_new.cpp │ ├── 020_RVO_NRVO.cpp │ ├── 016_assignment_via_constructor.cpp │ ├── 006_constructor_with_one_argument.cpp │ ├── 001_encapsulation.cpp │ ├── 015_move_assignment.cpp │ ├── 021_RAII.cpp │ ├── 009_transform_constuctors_and_operations.cpp │ ├── 013_simple_initializers_in_cpp11.cpp │ ├── 011_destructors.cpp │ ├── 014_move_constructor.cpp │ ├── 008_default_copy_constructor_and_assign_operator.cpp │ ├── 010_initializer_list_vs_constructor_body.cpp │ ├── 007_private_constructor.cpp │ └── 002_namespaces.cpp └── c_homework │ ├── test_input │ └── team_projects.c ├── .gitignore ├── README.md ├── examples_valgrind ├── static.c ├── CMakeLists.txt ├── uninit_read.c ├── leak.c ├── oob_access.c └── use_after_free.c ├── 2017_2 └── examples │ ├── lecture3 │ ├── 028_elimination.cpp │ ├── 025_contr_order.cpp │ ├── 033_observer.cpp │ ├── 030_adapter.cpp │ ├── 031_bridge.cpp │ ├── 026_diamond_inheritance.cpp │ ├── 029_abstract_factory.cpp │ ├── 027_RTTI.cpp │ ├── CMakeLists.txt │ ├── 032_command.cpp │ └── 034_visitor.cpp │ ├── patterns │ ├── CMakeLists.txt │ ├── 033_observer.cpp │ ├── 030_adapter.cpp │ ├── 031_bridge.cpp │ ├── 029_abstract_factory.cpp │ ├── 032_command.cpp │ └── 034_visitor.cpp │ └── stl │ ├── CMakeLists.txt │ ├── 040_erase_remove.cpp │ ├── 042_crtp_class.cpp │ ├── 041_equality_equivalent.cpp │ ├── 035_vector.cpp │ ├── 036_vector_2.cpp │ ├── 037_vector_3.cpp │ ├── 038_bad_lru_cache.cpp │ └── 039_good_lru_cache.cpp └── compiler.md /drafts/images: -------------------------------------------------------------------------------- 1 | ../images -------------------------------------------------------------------------------- /examples_gdb/expr.txt: -------------------------------------------------------------------------------- 1 | 1+*2 2 | -------------------------------------------------------------------------------- /images/cpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leshiy1295/technopark_c_c_plus_plus/HEAD/images/cpp.png -------------------------------------------------------------------------------- /images/gcc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leshiy1295/technopark_c_c_plus_plus/HEAD/images/gcc.png -------------------------------------------------------------------------------- /images/llvm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leshiy1295/technopark_c_c_plus_plus/HEAD/images/llvm.png -------------------------------------------------------------------------------- /images/osx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leshiy1295/technopark_c_c_plus_plus/HEAD/images/osx.png -------------------------------------------------------------------------------- /examples/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "cstdlib": "c" 4 | } 5 | } -------------------------------------------------------------------------------- /examples/lecture2/032_static_inline_second.c: -------------------------------------------------------------------------------- 1 | #include "032_static_inline.h" 2 | 3 | void bar() { 4 | foo(); 5 | foo2(); 6 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /examples_valgrind/build 2 | *.kate-swp 3 | .ipynb_checkpoints 4 | 2017_2/examples/lecture3/cmake-build-debug 5 | 2017_2/examples/lecture3/.idea 6 | -------------------------------------------------------------------------------- /examples/lecture2/032_static_inline.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static inline void foo() { 4 | printf("foo()\n"); 5 | } 6 | 7 | inline void foo2() { 8 | printf("foo2()\n"); 9 | } -------------------------------------------------------------------------------- /examples/lecture2/032_static_inline_main.c: -------------------------------------------------------------------------------- 1 | #include "032_static_inline.h" 2 | 3 | extern void foo2(); 4 | void bar(); 5 | 6 | int main() { 7 | foo(); 8 | bar(); 9 | foo2(); 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Дополнительные материалы к курсу "Углубленное программирование на C/C++" 2 | 3 | 4 | 5 | 1. [Работа с компилятором](compiler.md) 6 | 2. [Работа с Valgrind](valgrind.md) 7 | 3. [Отладка программ с помощью GDB](gdb-intro.md) 8 | -------------------------------------------------------------------------------- /examples_valgrind/static.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | char dest[2]; 4 | 5 | int main(void) 6 | { 7 | char src[2]; 8 | src[0] = 'a'; 9 | src[1] = 'b'; 10 | for (int i = 0; i <= 2; i++) 11 | dest[i] = src[i]; 12 | printf("%s\n", dest); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /examples/lecture1/014_reading_to_static_buffer.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | char buf[80]; 5 | // NON-COMPLIANT 6 | scanf("%s", buf); 7 | // COMPLIANT 8 | //scanf("%80s", buf); 9 | printf("%s\n", buf); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /examples/lecture2/005_fork_bomb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | for (int i = 0; i < 10; ++i) { 6 | printf("Time to fork\n"); 7 | fork(); 8 | printf("Hello world\n"); 9 | } 10 | printf("Bye world\n"); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /examples/lecture1/017_double_prefix_operators.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | int a = 5; 5 | printf("%d, %d\n", !!a, ~~a); 6 | int b = 5 + !!a; 7 | int c = 5 - ~~b; 8 | if (!!a && ~~b) { 9 | printf("%d\n", c); 10 | } 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /examples_valgrind/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(vg_examples C) 2 | 3 | set(CMAKE_C_FLAGS "-std=c99 -ggdb3") 4 | 5 | add_executable(uninit_read uninit_read.c) 6 | add_executable(oob_access oob_access.c) 7 | add_executable(use_after_free use_after_free.c) 8 | add_executable(leak leak.c) 9 | add_executable(static static.c) 10 | 11 | -------------------------------------------------------------------------------- /examples/lecture1/001_memory_classes_1.h: -------------------------------------------------------------------------------- 1 | #ifndef _001_MEMORY_CLASSES_1_H 2 | #define _001_MEMORY_CLASSES_1_H 3 | 4 | //static const char *SECRET_WORD; // Can not use anywhere else => not used 5 | 6 | extern const char *NOT_SECRET_WORD; 7 | 8 | //static void bar(); // Can not use anywhere else => not used 9 | 10 | extern void foo(); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /examples/lecture1/019_redundant_specifiers.c: -------------------------------------------------------------------------------- 1 | #include // NULL declaration 2 | 3 | int main(int argc, char *argv[]) { 4 | const int const *bad_v1a = NULL; // both specifiers apply to int 5 | const int const *bad_v1b = NULL; 6 | static static int bad_v2 = 0; 7 | 8 | const int *v1a = NULL; 9 | int const * const v1b = NULL; 10 | static int v2 = 0; 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /examples/lecture2/007_exec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | printf("Будет выполнена программа %s...\n", argv[0]); 7 | printf("Выполняется %s\n", argv[0]); 8 | // execv(argv[0], argv); 9 | execl(argv[0], " ", "Hello", "World!", NULL); 10 | printf("system status_code=%d\n", system("ls -la >/dev/null 2>&1")); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /examples_valgrind/uninit_read.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | char *data = malloc(5); 7 | data[0] = 'a'; 8 | data[1] = 'b'; 9 | data[1] = 'c'; 10 | printf("data[2] is equal to 0x%02x\n", data[2]); 11 | if (data[2] == 'c') 12 | printf("It is 'c'\n"); 13 | else 14 | printf("It is not 'c'\n"); 15 | free(data); 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /examples/lecture1/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ("$(STD)", "") 2 | STD_OPTION = 3 | else 4 | STD_OPTION = -std=gnu$(STD) 5 | endif 6 | ADDITIONAL_OPTIONS ?= 7 | OPTIONS ?= $(ADDITIONAL_OPTIONS) $(STD_OPTION) -Wall -Wpedantic 8 | OUT_FILE ?= a.out 9 | 10 | default: run clean_after 11 | 12 | clean: clean_before 13 | 14 | 15 | clean%: 16 | @rm -f $(OUT_FILE) 17 | 18 | build: clean_before 19 | gcc $(FILE) $(OPTIONS) -o $(OUT_FILE) 20 | 21 | run: build 22 | ./$(OUT_FILE) $(ARGS) 23 | -------------------------------------------------------------------------------- /examples/lecture2/004_fork_basic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | int pid = fork(); 7 | 8 | if (pid == -1) { 9 | printf("fork failed\n"); 10 | return 1; 11 | } 12 | 13 | if (pid == 0) { 14 | sleep(1); 15 | printf("CHILD: Hello world\n"); 16 | exit(0); 17 | } 18 | 19 | printf("PARENT: forked child with pid %d\n", pid); 20 | 21 | return 0; 22 | } -------------------------------------------------------------------------------- /examples/lecture2/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ("$(STD)", "") 2 | STD_OPTION = 3 | else 4 | STD_OPTION = -std=gnu$(STD) 5 | endif 6 | ADDITIONAL_OPTIONS ?= 7 | OPTIONS ?= $(ADDITIONAL_OPTIONS) $(STD_OPTION) -Wall -Wpedantic 8 | OUT_FILE ?= a.out 9 | 10 | default: run clean_after 11 | 12 | clean: clean_before 13 | 14 | 15 | clean%: 16 | @rm -f $(OUT_FILE) 17 | 18 | build: clean_before 19 | gcc $(FILE) $(OPTIONS) -o $(OUT_FILE) 20 | 21 | run: build 22 | ./$(OUT_FILE) $(ARGS) 23 | -------------------------------------------------------------------------------- /examples/lecture3/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ("$(STD)", "") 2 | STD_OPTION = 3 | else 4 | STD_OPTION = -std=c++$(STD) 5 | endif 6 | ADDITIONAL_OPTIONS ?= 7 | OPTIONS ?= $(ADDITIONAL_OPTIONS) $(STD_OPTION) -Wall -Wpedantic 8 | OUT_FILE ?= a.out 9 | 10 | default: run clean_after 11 | 12 | clean: clean_before 13 | 14 | 15 | clean%: 16 | @rm -f $(OUT_FILE) 17 | 18 | build: clean_before 19 | g++ $(FILE) $(OPTIONS) -o $(OUT_FILE) 20 | 21 | run: build 22 | ./$(OUT_FILE) $(ARGS) 23 | -------------------------------------------------------------------------------- /examples/lecture3/023_noexcept_destructor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct A { 4 | /* BAD */ 5 | ~A() noexcept { // try to uncomment it 6 | throw "Exception"; 7 | } 8 | }; 9 | 10 | struct B { 11 | /* GOOD */ 12 | ~B() noexcept { 13 | } 14 | }; 15 | 16 | int main(int argc, char *argv[]) { 17 | try { 18 | A a; 19 | } catch(...) { 20 | std::cout << "catched"; 21 | } 22 | 23 | B b; 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /examples_valgrind/leak.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *my_strdup(const char *src) 6 | { 7 | size_t len = strlen(src); 8 | char *dest = malloc(len); 9 | memcpy(dest, src, len); 10 | dest[len] = '\0'; 11 | return dest; 12 | } 13 | 14 | int main(void) 15 | { 16 | const char hello[] = "Hello, world!"; 17 | char *copy = my_strdup(hello); 18 | printf("Result: '%s'\n", copy); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /examples/lecture3/019_delete_and_default_methods.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct A { 4 | private: 5 | int ipr; 6 | double dpr; 7 | public: 8 | A() = delete; 9 | A(int ipr, double dpr) : ipr(ipr), dpr(dpr) {} 10 | A(A &&) = default; 11 | A(A &) = default; 12 | A &operator=(A const &) = default; 13 | }; 14 | 15 | int main() { 16 | A //a1, 17 | a2(1, 4.2), 18 | a3(std::move(a2)), 19 | a4(a2); 20 | a4 = a3; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/lecture1/020_different_enum_types_comparison.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum apple {BRAEBURN, FUJI, GRANNY_SMITH, RED_DELICIOUS}; 5 | enum orange {BLOOD, NAVEL, BITTER, BERGAMOT, MANDARIN}; 6 | 7 | bool fun(enum apple v1, enum orange v2) { 8 | return v1 == v2; // Non-compliant 9 | } 10 | 11 | int main(int argc, char *argv[]) { 12 | if (fun(FUJI, NAVEL)) { 13 | printf("FUJI (%d) == NAVEL (%d)\n", FUJI, NAVEL); 14 | } 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /examples/lecture1/002_address_of_register_variable.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | register int a = 42; 5 | printf("Address of \"register\" variable a with value %d is %p\n", a, &a); // Compiler error 6 | // but in some compilers (like g++) 7 | // register specifier may be ignored 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /examples_valgrind/oob_access.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *my_strdup(const char *src) 6 | { 7 | size_t len = strlen(src); 8 | char *dest = malloc(len); 9 | memcpy(dest, src, len); 10 | dest[len] = '\0'; 11 | return dest; 12 | } 13 | 14 | int main(void) 15 | { 16 | const char hello[] = "Hello, world!"; 17 | char *copy = my_strdup(hello); 18 | printf("Result: '%s'\n", copy); 19 | free(copy); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/028_elimination.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct A {}; 4 | 5 | struct B : public A { 6 | int a; 7 | }; 8 | 9 | struct C : public A { 10 | int var; 11 | A a; 12 | }; 13 | 14 | struct D : public A { 15 | int a; 16 | B b; 17 | // char c; 18 | }; 19 | 20 | int main() { 21 | std::cout << sizeof(A) << std::endl; 22 | std::cout << sizeof(B) << std::endl; 23 | std::cout << sizeof(C) << std::endl; 24 | std::cout << sizeof(D) << std::endl; 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /examples/lecture2/012_named_fifo_reader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | int fd; 8 | char *hellofifo = "/tmp/hellofifo"; 9 | char buf[100]; 10 | 11 | if ((fd = open(hellofifo, O_RDONLY)) == -1) { 12 | printf("Pipe not exists\n"); 13 | return 1; 14 | } 15 | 16 | printf("Connected!\n"); 17 | read(fd, buf, sizeof(buf)); 18 | printf("Received %s\n", buf); 19 | close(fd); 20 | } -------------------------------------------------------------------------------- /examples/lecture3/004_default_contructor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Sample { 4 | Sample(int ipr = 0, double dpr = 0.0): ipr(ipr), dpr(dpr) {} 5 | void print() { 6 | std::cout << ipr << " " << dpr << " " << std::endl; 7 | } 8 | private: 9 | int ipr; 10 | double dpr; 11 | }; 12 | 13 | int main(int argc, char *argv[]) { 14 | Sample s; 15 | s.print(); 16 | Sample s1(10); 17 | s1.print(); 18 | Sample s2(10, 5); 19 | s2.print(); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /examples_valgrind/use_after_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *my_strdup(const char *src) 6 | { 7 | size_t len = strlen(src); 8 | char *dest = malloc(len); 9 | memcpy(dest, src, len); 10 | dest[len] = '\0'; 11 | return dest; 12 | } 13 | 14 | int main(void) 15 | { 16 | const char hello[] = "Hello, world!"; 17 | char *copy = my_strdup(hello); 18 | free(copy); 19 | printf("Result: '%s'\n", copy); 20 | free(copy); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/lecture3/003_initialization_without_constructor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Sample { 5 | int int_prm; 6 | double dbl_prm; 7 | std::string std_prm; 8 | void print() { 9 | std::cout << int_prm << " " << dbl_prm << " " << std_prm << std::endl; 10 | } 11 | }; 12 | 13 | int main(int argc, char *argv[]) { 14 | Sample sample = {1, -3.14, "dictum factum"}; 15 | sample.print(); 16 | Sample cpp11sample{1, -3.14, "dictum factum"}; // c++11 17 | sample.print(); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /examples/lecture3/022_undefined_sizeof.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | int i = 0; 5 | int b[10000] = {0}; 6 | /* BAD - i will not change */ 7 | int j = sizeof(i = 1234); 8 | std::cout << i << " " << j << std::endl; 9 | j = sizeof(b[i++]); 10 | std::cout << i << " " << j << std::endl; 11 | 12 | /* GOOD */ 13 | i = 1234; j = sizeof(i); 14 | std::cout << i << " " << j << std::endl; 15 | i++; j = sizeof(b[i]); 16 | std::cout << i << " " << j << std::endl; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /2017_2/examples/patterns/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(patterns) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -Wall -ggdb3") 7 | 8 | add_executable(029_abstract_factory 029_abstract_factory.cpp) 9 | add_executable(030_adapter 030_adapter.cpp) 10 | add_executable(031_bridge 031_bridge.cpp) 11 | add_executable(032_command 032_command.cpp) 12 | add_executable(033_observer 033_observer.cpp) 13 | add_executable(034_visitor 034_visitor.cpp) 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/lecture1/001_memory_classes.c: -------------------------------------------------------------------------------- 1 | // To run example one need to compile two .c files together 2 | #include "001_memory_classes_1.h" 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | // Automatic memory class 7 | auto int i = 0; 8 | int j = 1; 9 | // Register memory class 10 | register int k = 1; 11 | foo(); 12 | foo(); 13 | //bar(); // Compilation error - implementation not found 14 | //printf("%s\n", SECRET_WORD); // Runtime error - value not found 15 | printf("%s\n", NOT_SECRET_WORD); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /examples/lecture1/012_buffer_overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define MAX_STR_SIZE 80 6 | 7 | void foo(char *s) { 8 | char buf[MAX_STR_SIZE]; 9 | strcpy(buf, s); 10 | printf("From foo: %s\n", buf); 11 | } 12 | 13 | int main(int argc, char *argv[]) { 14 | int N = 100; 15 | char *s = (char *)malloc((N + 1) * sizeof(char)); 16 | for (size_t i = 0; i < N; ++i) { 17 | s[i] = 'A'; 18 | } 19 | s[N] = '\0'; 20 | printf("From main: %s\n", s); 21 | foo(s); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /examples/lecture2/023_c11_atomic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | _Atomic int acnt; 5 | int cnt; 6 | void *count(void *input) { 7 | for (int i = 0; i < 10000; ++i) { acnt++; cnt++; } 8 | pthread_exit(NULL); 9 | } 10 | 11 | int main() { 12 | pthread_t tid[10]; 13 | for (int i = 0; i < 10; i++) pthread_create(&tid[i], NULL, count, NULL); 14 | for (int i = 0; i < 10; i++) pthread_join(tid[i], NULL); 15 | printf("the value of acnt is %d\n", acnt); 16 | printf("the value of cnt is %d\n", cnt); 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /examples/lecture2/030___builtin_expect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define unlikely(expr) __builtin_expect(!!(expr), 0) 6 | #define likely(expr) __builtin_expect(!!(expr), 1) 7 | 8 | void foo() { 9 | printf("foo()\n"); 10 | } 11 | 12 | void bar() { 13 | printf("bar()\n"); 14 | } 15 | 16 | int main(int argc, char *argv[]) { 17 | srand(time(NULL)); 18 | 19 | int a = rand() % 10; 20 | 21 | if (unlikely(a > 8)) // false in 80% of cases 22 | foo(); 23 | else 24 | bar(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /examples/lecture1/022_continue.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void foo1() { 4 | printf("foo1()\n"); 5 | for (int i = 0; i < 10; i++) { 6 | if (i == 5) { 7 | continue; // Non-compliant 8 | } 9 | printf("i = %d\n", i); 10 | } 11 | } 12 | 13 | void foo2() { 14 | printf("foo2()\n"); 15 | for (int i = 0; i < 10; i++) { 16 | if (i != 5) { // Compliant 17 | printf("i = %d\n", i); 18 | } 19 | } 20 | } 21 | 22 | int main(int argc, char *argv[]) { 23 | foo1(); 24 | foo2(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /2017_2/examples/stl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(stl) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -Wall -ggdb3") 7 | 8 | add_executable(035_vector 035_vector.cpp) 9 | add_executable(036_vector_2 036_vector_2.cpp) 10 | add_executable(037_vector_3.cpp 037_vector_3.cpp) 11 | add_executable(040_erase_remove 040_erase_remove.cpp) 12 | add_executable(041_equality_equivalent 041_equality_equivalent.cpp) 13 | add_executable(042_crtp_class 042_crtp_class.cpp) 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/lecture3/017_defaults_constructors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct A { 4 | A() { 5 | std::cout << "A()" << std::endl; 6 | } 7 | A(A &&a) { 8 | std::cout << "A(A &&a)" << std::endl; 9 | } 10 | }; 11 | 12 | struct B { 13 | B() { 14 | std::cout << "B()" << std::endl; 15 | } 16 | B(B &&b) { 17 | std::cout << "B(B &&b)" << std::endl; 18 | } 19 | }; 20 | 21 | struct C { 22 | private: 23 | A a; 24 | B b; 25 | }; 26 | 27 | int main(int argc, char *argv[]) { 28 | C c1; 29 | C c2(std::move(c1)); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /examples/lecture1/021_nonnull_pointers.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // NON-COMPLIANT 4 | __attribute__((returns_nonnull)) 5 | __attribute__((nonnull)) 6 | int *nonnull(int *parameter) { 7 | parameter = NULL; // "parameter" is marked "nonnull" 8 | // but is set to null. 9 | return NULL; // function's return value is marked 10 | // "nonnull" but null is returned 11 | } 12 | 13 | int main(int argc, char *argv[]) { 14 | nonnull(NULL); // "parameter" to this call is marked 15 | // "nonnull", but null is passed. 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /examples/lecture3/018_trivial_constructors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct A { 4 | int a; 5 | void print() { 6 | std::cout << "A::print(" << a << ")" << std::endl; 7 | } 8 | }; 9 | 10 | struct B { 11 | int b; 12 | void print() { 13 | std::cout << "B::print(" << b << ")" << std::endl; 14 | } 15 | }; 16 | 17 | struct C { 18 | A a; 19 | B b; 20 | void print() { 21 | a.print(); 22 | b.print(); 23 | } 24 | }; 25 | 26 | int main(int argc, char *argv[]) { 27 | char buffer[sizeof(C)]; 28 | reinterpret_cast(buffer)->print(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/lecture3/024_using_conflicts.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace N1 { 4 | void foo() { 5 | std::cout << "N1::foo()" << std::endl; 6 | } 7 | void bar() { 8 | std::cout << "N1::bar()" << std::endl; 9 | } 10 | } 11 | 12 | namespace N2 { 13 | void foo() { 14 | std::cout << "N2::foo()" << std::endl; 15 | } 16 | void baz() { 17 | std::cout << "N2::baz()" << std::endl; 18 | } 19 | } 20 | 21 | int main() { 22 | using namespace N1; 23 | //using namespace N2; 24 | using N2::baz; 25 | foo(); 26 | bar(); 27 | baz(); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /examples/lecture2/031_inline_functions.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | inline __attribute__((always_inline)) void foo1() { 4 | printf("foo1()\n"); 5 | } 6 | 7 | /*inline __attribute__((noinline)) void foo2() { 8 | printf("foo2()\n"); 9 | }*/ 10 | 11 | __attribute__((always_inline)) void foo3() { 12 | printf("foo3()\n"); 13 | } 14 | 15 | __attribute__((noinline)) void foo4() { 16 | printf("foo4()\n"); 17 | } 18 | 19 | void foo5() { 20 | printf("foo5()\n"); 21 | } 22 | 23 | int main(int argc, char *argv[]) { 24 | foo1(); 25 | //foo2(); 26 | foo3(); 27 | foo4(); 28 | foo5(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /examples/lecture3/005_required_default_constructor_for_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Sample { 4 | //Sample() {} 5 | Sample(int a/* = 0*/): a(a) {} 6 | 7 | void print() { 8 | std::cout << "print()" << std::endl; 9 | } 10 | 11 | private: 12 | int a; 13 | }; 14 | 15 | int main(int argc, char *argv[]) { 16 | const int N = 3; 17 | Sample samples[N]; 18 | for (int i = 0; i < N; ++i) { 19 | samples1[i].print(); 20 | } 21 | Sample *samples1 = new Sample[N]; 22 | for (int i = 0; i < N; ++i) { 23 | samples1[i].print(); 24 | } 25 | delete []samples1; 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /2017_2/examples/stl/040_erase_remove.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | int main() { 14 | vector e = {1, 2, 3, 4, 5, 6}; 15 | auto pred = [&](int el) -> bool { return el < 5; }; 16 | e.erase(std::remove_if(e.begin(), e.end(), pred), e.end()); 17 | // e.erase(std::remove_if(e.begin(), e.end(), std::bind2nd(std::less(), 5)), 18 | // e.end()); 19 | for (int el : e) { 20 | std::cout << el << " "; 21 | } 22 | std::cout << endl; 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /examples/lecture1/001_memory_classes_1.c: -------------------------------------------------------------------------------- 1 | #include "001_memory_classes_1.h" 2 | #include 3 | 4 | // Static variable inside file with inner linking 5 | static const char *SECRET_WORD = "secret"; 6 | 7 | // Static variable inside file with outer linking 8 | const char *NOT_SECRET_WORD = "not secret"; 9 | 10 | // Static function with inner linking 11 | static void bar() { 12 | printf("%s\n", NOT_SECRET_WORD); 13 | } 14 | 15 | // Static function inside file with outer linking 16 | void foo() { 17 | // Static without linking inside block 18 | static int v = 0; 19 | printf("%d\n", v++); 20 | } 21 | 22 | /*int main() { 23 | foo(); 24 | bar(); 25 | printf("%s\n", SECRET_WORD); 26 | printf("%s\n", NOT_SECRET_WORD); 27 | return 0; 28 | }*/ 29 | -------------------------------------------------------------------------------- /examples/lecture2/027_packing_structs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct first { 5 | int id; 6 | char name[15]; 7 | double amount; 8 | _Bool active; 9 | }; 10 | 11 | struct second { 12 | int id; 13 | char name[15]; 14 | double amount; 15 | _Bool active; 16 | }; 17 | 18 | struct third { 19 | int id; 20 | char name[15]; 21 | _Bool active; 22 | double amount; 23 | }; 24 | 25 | int main(int argc, char *argv[]) { 26 | printf("Components:\nint: %ld\nchar[15]: %ld\ndouble: %ld\n_Bool: %ld\n", sizeof(int), sizeof(char[15]), sizeof(double), sizeof(_Bool)); 27 | printf("Summary:\ns1: %ld\ns2: %ld\ns3: %ld\n", sizeof(struct first), sizeof(struct second), sizeof(struct third)); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /examples/lecture1/008_const_qualifier.c: -------------------------------------------------------------------------------- 1 | void foo(int a, const int b, int const c, int *d, const int *e, int * const f, const int * const g) { 2 | a = 10; 3 | //b = 20; 4 | //c = 30; 5 | *d = a; 6 | d = &a; 7 | //*e = b; 8 | e = &b; 9 | *f = c; 10 | //f = &c; 11 | //*g = a; 12 | //g = &a; 13 | 14 | // compatibility 15 | a = b; 16 | //b = a; 17 | //d = e; 18 | d = f; 19 | //d = g; 20 | d = &a; 21 | e = d; 22 | e = f; 23 | e = g; 24 | e = &a; 25 | //f = d; 26 | //f = e; 27 | //f = g; 28 | //f = &a; 29 | //g = d; 30 | //g = e; 31 | //g = f; 32 | //g = &a; 33 | } 34 | 35 | int main(int argc, char *argv[]) { 36 | int a = 0; 37 | foo(a, a, a, &a, &a, &a, &a); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /examples/lecture1/018_dead_stores.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int pow1(int a, int b) { 4 | printf("pow1()\n"); 5 | if (b == 0) { 6 | return 0; 7 | } 8 | int x = a; 9 | for (int i = 1; i < b; i++) { 10 | x = x * a; // Dead store because the last return 11 | // statement should return x instead 12 | // of returning a 13 | } 14 | return a; 15 | } 16 | 17 | int pow2(int a, int b) { 18 | printf("pow2()\n"); 19 | if (b == 0) { 20 | return 0; 21 | } 22 | int x = a; 23 | for (int i = 1; i < b; i++) { 24 | x = x * a; 25 | } 26 | return x; 27 | } 28 | 29 | int main(int argc, char *argv[]) { 30 | printf("%d\n", pow1(2, 4)); 31 | printf("%d\n", pow2(2, 4)); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /examples/lecture2/012_named_fifo_writer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | int fd; 8 | char *hellofifo = "/tmp/hellofifo"; 9 | 10 | unlink(hellofifo); 11 | 12 | if (mkfifo(hellofifo, 0777) != 0) { 13 | printf("Failed to create named fifo\n"); 14 | return 1; 15 | } 16 | 17 | printf("Waiting for reader...\n"); 18 | fd = open(hellofifo, O_WRONLY); 19 | printf("Reader found!\n"); 20 | sleep(10); 21 | 22 | static const char message[] = "Hello reader!"; 23 | 24 | write(fd, message, sizeof(message)); 25 | printf("Message %s sent\n", message); 26 | close(fd); 27 | 28 | if (unlink(hellofifo)) { 29 | printf("Failed to remove named fifo\n"); 30 | } 31 | } -------------------------------------------------------------------------------- /examples/lecture1/004_static_arrays_initialization.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) { 4 | int a[] = {1, 2, 3}; 5 | int b[5] = {1, 2, 3}; 6 | int c[7] = {1, [5] = 10, 20, [1] = 2}; 7 | int d[10] = {[0 ... 9] = -1}; // Extension to GCC compiler 8 | for (size_t i = 0; i < sizeof(a) / sizeof(*a); ++i) { 9 | printf("%d ", a[i]); 10 | } 11 | printf("\n"); 12 | for (size_t i = 0; i < sizeof(b) / sizeof(*b); ++i) { 13 | printf("%d ", b[i]); 14 | } 15 | printf("\n"); 16 | for (size_t i = 0; i < sizeof(c) / sizeof(*c); ++i) { 17 | printf("%d ", c[i]); 18 | } 19 | printf("\n"); 20 | for (size_t i = 0; i < sizeof(d) / sizeof(*d); ++i) { 21 | printf("%d ", d[i]); 22 | } 23 | printf("\n"); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /examples/lecture2/013_alarm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int counter = 0; 6 | 7 | void handler(int signum) { 8 | printf("Handler called for signum %d\n", signum); 9 | if (signum == SIGALRM) { 10 | printf("Counter = %d\n", counter); 11 | alarm(1); 12 | } 13 | 14 | if (signum == SIGINT) { 15 | // убрать обработчик сигнала - обработка по умолчанию 16 | signal(signum, SIG_DFL); 17 | } 18 | } 19 | 20 | int main() { 21 | printf("My pid is %d\n", getpid()); 22 | 23 | if (signal(SIGINT, handler) == SIG_ERR) { 24 | printf("Failed to register handler for SIGINT\n"); 25 | } 26 | if (signal(SIGALRM, handler) == SIG_ERR) { 27 | printf("Failed to register handler for SIGALRM\n"); 28 | } 29 | while (1) { ++counter; } 30 | return 0; 31 | } -------------------------------------------------------------------------------- /examples/lecture3/012_placement_new.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A { 4 | private: 5 | int counter; 6 | public: 7 | A() { 8 | std::cout << "A()" << std::endl; 9 | } 10 | A(int counter) : counter(counter) { 11 | std::cout << "A(int)" << std::endl; 12 | } 13 | void inc() { 14 | ++counter; 15 | } 16 | void print() { 17 | std::cout << counter << std::endl; 18 | } 19 | ~A() { 20 | std::cout << "~A()" << std::endl; 21 | } 22 | }; 23 | 24 | int main(int argc, char *argv[]) { 25 | char *buffer = new char[sizeof(A)]; 26 | A *a1 = new (buffer) A(0); 27 | a1->print(); 28 | a1->inc(); 29 | a1->inc(); 30 | a1->print(); 31 | a1->~A(); 32 | A *a2 = new (buffer) A(); 33 | a2->print(); 34 | a2->inc(); 35 | a2->inc(); 36 | a2->print(); 37 | a2->~A(); 38 | delete []buffer; 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /examples/lecture2/011_popen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define MAX_LEN 80 5 | 6 | // try ARGS="\"ls\" \"sort -r\"" 7 | int main(int argc, char *argv[]) { 8 | FILE *pipe_in, *pipe_out; 9 | char read_buf[MAX_LEN]; 10 | 11 | if ((pipe_in = popen(argv[1], "r")) == NULL) { 12 | printf("Failed to create pipe_in\n"); 13 | exit(1); 14 | } 15 | 16 | if ((pipe_out = popen(argv[2], "w")) == NULL) { 17 | printf("Failed to create pipe_out\n"); 18 | if (pclose(pipe_in)) { 19 | printf("Failed to close pipe_in\n"); 20 | } 21 | exit(1); 22 | } 23 | 24 | while (fgets(read_buf, MAX_LEN, pipe_in)) { 25 | printf("%s", read_buf); 26 | fputs(read_buf, pipe_out); 27 | } 28 | 29 | if (pclose(pipe_in)) { 30 | printf("Failed to close pipe_in\n"); 31 | } 32 | 33 | if (pclose(pipe_out)) { 34 | printf("Failed to close pipe_out\n"); 35 | } 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /examples/lecture1/016_wrong_pointers_operations.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // bzero 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | //memcpy(NULL, argv[0], strlen(argv[0])); // ignoring nonnull 8 | char *s = (char *)malloc(10 * sizeof(char)); 9 | if (!s) { 10 | exit(1); 11 | } 12 | bzero(s, 0); 13 | char *s2 = (char *)malloc(10 * sizeof(char)); 14 | if (!s2) { 15 | //free(s); // Don't forget to free even with exit... 16 | exit(1); // Don't use exit, system etc.. Don't use qsort, for instance, because it takes user function, whick can be unpredictable 17 | } 18 | char buf[100]; 19 | //free(s); // Don't forget to free dynamically allocated memory 20 | s = realloc(s, 0); // s may become NULL 21 | free(s2); 22 | printf("&s: %p\n", s); 23 | //printf("*s: %c", *s); // NULL pointers should not be dereferenced 24 | //free(buf); // Don't free stack memory 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /examples/lecture2/024_c11_cas.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | _Atomic int lock = 0; 6 | int lock_count = 0; 7 | int unlock_count = 0; 8 | 9 | void *counting(void *input) { 10 | int expected = 0; 11 | for(int i = 0; i < 100000; i++) 12 | { 13 | unlock_count++; 14 | while(!atomic_compare_exchange_weak(&lock,&expected,1)) //if the lock is 0(unlock), then set it to 1(lock). 15 | expected = 0; //if the CAS fails, the expected will be set to 1, so we need to change it to 0 again. 16 | lock_count++; 17 | lock = 0; 18 | } 19 | pthread_exit(NULL); 20 | } 21 | 22 | int main() { 23 | pthread_t tid[10]; 24 | 25 | for(int i = 0; i < 10; i++) { 26 | pthread_create(&tid[i], NULL, counting, NULL); 27 | } 28 | for(int i = 0; i < 10; i++) 29 | pthread_join(tid[i], NULL); 30 | 31 | printf("the value of lock_count is %d\n",lock_count); 32 | printf("the value of unlock_count is %d\n",unlock_count); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /examples/lecture3/020_RVO_NRVO.cpp: -------------------------------------------------------------------------------- 1 | // Run with and without -fno-elide-constructors 2 | #include 3 | 4 | struct A { 5 | A() { 6 | std::cout << "A()" << std::endl; 7 | } 8 | 9 | A(A &&a) { 10 | std::cout << "A(A &&)" << std::endl; 11 | } 12 | 13 | A(A const &a) { 14 | std::cout << "A(A const &)" << std::endl; 15 | } 16 | 17 | A &operator=(A const &a) { 18 | std::cout << "A &operator=(A const &a)" << std::endl; 19 | return *this; 20 | } 21 | }; 22 | 23 | A example_RVO(A a) { 24 | std::cout << "inside example_RVO" << std::endl; 25 | return A(a); 26 | } 27 | 28 | A example_NRVO(A a) { 29 | std::cout << "inside example_NRVO" << std::endl; 30 | A newA(a); 31 | return newA; 32 | } 33 | 34 | int main(int argc, char *argv[]) { 35 | A a1; 36 | std::cout << "before example_RVO" << std::endl; 37 | A a2 = example_RVO(a1); 38 | std::cout << "between example_RVO and example_NRVO" << std::endl; 39 | a1 = example_NRVO(a2); 40 | std::cout << "after example_NRVO" << std::endl; 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /examples/lecture2/026_posix_memalign.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include // sysconf, _SC_LEVEL1_DCACHE_LINESIZE 3 | #include // posix_memalign 4 | #include // memcpy 5 | #include // uint64_t 6 | 7 | int main(int argc, char *argv[]) { 8 | int b[7] = {1, [5] = 10, 20, [1] = 2}; 9 | int *p = NULL; 10 | int errflag; 11 | 12 | long l1dcls = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); 13 | if (l1dcls == -1) { 14 | l1dcls = sizeof(void *); 15 | } 16 | errflag = posix_memalign((void **)&p, l1dcls, sizeof b); 17 | if (!errflag) { 18 | printf("\nL1d cache line size is %ld\n", l1dcls); 19 | printf("p (mod L1d) and &p (mod L1d) are %p (%ld) and %p (%ld)\n", p, (uint64_t)p % l1dcls, &p, (uint64_t)&p % l1dcls); 20 | p = memcpy(p, b, sizeof(b)); 21 | for (size_t i = 0; i < sizeof(b) / sizeof(b[0]); ++i) { 22 | printf("%d ", b[i]); 23 | } 24 | printf("\n"); 25 | free(p); 26 | } 27 | else { 28 | printf("posix_memalign error: %d\n", errflag); 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /examples/lecture3/016_assignment_via_constructor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class resource {}; 4 | typedef resource *resource_t; 5 | resource_t acquire(const std::string &name) { 6 | return nullptr; 7 | } 8 | void release(resource_t r) {} 9 | 10 | class T { 11 | private: 12 | resource_t handle; 13 | public: 14 | explicit T(const std::string &_name) : handle {::acquire(_name)} { 15 | std::cout << "T()" << std::endl; 16 | } 17 | 18 | T(T &&rhs) : handle{rhs.handle} { 19 | std::cout << "T(T &&)" << std::endl; 20 | rhs.handle = nullptr; 21 | } 22 | 23 | T &operator=(T &&rhs) { 24 | std::cout << "T &operator(T &&)" << std::endl; 25 | T copy{std::move(rhs)}; 26 | std::swap(handle, copy.handle); 27 | return *this; 28 | } 29 | ~T() { 30 | std::cout << "~T()" << std::endl; 31 | ::release(handle); 32 | } 33 | }; 34 | 35 | int main(int argc, char *argv[]) { 36 | T a("string"); 37 | T b(std::move(a)); 38 | b = std::move(a); 39 | std::cout << "end of scope" << std::endl; 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /2017_2/examples/stl/042_crtp_class.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | template struct Base { 14 | void interface() { static_cast(this)->implementation(); } 15 | void implementation() { std::cout << "Implementation Base" << std::endl; } 16 | }; 17 | 18 | struct Derived1 : Base { 19 | void implementation() { std::cout << "Implementation Derived1" << std::endl; } 20 | }; 21 | 22 | struct Derived2 : Base { 23 | void implementation() { std::cout << "Implementation Derived2" << std::endl; } 24 | }; 25 | 26 | struct Derived3 : Base {}; 27 | 28 | template void execute(Base &base) { base.interface(); } 29 | 30 | int main() { 31 | Derived1 d1; 32 | execute(d1); 33 | 34 | Derived2 d2; 35 | execute(d2); 36 | 37 | Derived3 d3; 38 | execute(d3); 39 | 40 | int i = INT_MAX + 100; 41 | std::cout << std::endl; 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/025_contr_order.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace { 4 | class A { 5 | public: 6 | A() { std::cout << "ctor A()" << std::endl; } 7 | explicit A(int a) { std::cout << "ctor A() from int" << std::endl; } 8 | ~A() { std::cout << "dtor ~A()" << std::endl; } 9 | virtual void foo() { std::cout << std::endl << std::endl; } 10 | }; 11 | 12 | class B : public A { 13 | public: 14 | B() : a(5) { std::cout << "ctor B()" << std::endl; } 15 | ~B() { std::cout << "dtor ~B()" << std::endl; } 16 | A a; 17 | }; 18 | 19 | class Alpha { 20 | public: 21 | Alpha() { std::cout << "ctor Alpha()" << std::endl; } 22 | ~Alpha() { std::cout << "dtor ~Alpha()" << std::endl; } 23 | }; 24 | 25 | class C : public B, public Alpha { 26 | public: 27 | C() { std::cout << "ctor C()" << std::endl; } 28 | ~C() { std::cout << "dtor ~C()" << std::endl; } 29 | }; 30 | 31 | class D { 32 | public: 33 | D() { std::cout << "ctor D()" << std::endl; } 34 | ~D() { std::cout << "dtor ~D()" << std::endl; } 35 | C c; 36 | }; 37 | } // namespace diamond_problem 38 | 39 | 40 | int main() { 41 | D d; 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /examples/lecture1/010_restrict_and_volatile_pointers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | int N = 10; 6 | int k = 4; 7 | int result1 = 0; 8 | volatile int result2 = 0; 9 | // restrict int result3 = 0; // Compilation error - only porinters can be restricted 10 | int *volatile a = (int *)malloc(N * sizeof(int)); 11 | if (a) { 12 | result1 = a[k]; 13 | result1 = a[k]; // Shouldn't be removed, because of a is volatile 14 | free(a); 15 | } 16 | int *restrict b = (int *)malloc(N * sizeof(int)); 17 | if (b) { 18 | result1 = b[k]; 19 | result1 = b[k]; // Can be optimized, because b is restrict 20 | free(b); 21 | } 22 | int *c = (int *)malloc(N * sizeof(int)); 23 | if (c) { 24 | result1 = c[k]; 25 | result1 = c[k]; // ?, but by default - pessimistic strategy 26 | free(c); 27 | } 28 | result1 = result2; 29 | result1 = result2; // Should not be removed, because result2 is volatile 30 | printf("result1: %d, result2: %d\n", result1, result2); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /examples/lecture3/006_constructor_with_one_argument.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Sample { 4 | Sample(int prm = 0, double drm = 0): _prm(prm), _drm(drm) {} 5 | void print() { 6 | std::cout << _prm << std::endl; 7 | } 8 | private: 9 | int _prm; 10 | double _drm; 11 | }; 12 | 13 | int main(int argc, char *argv[]) { 14 | Sample sample1(10), 15 | sample2 = Sample(10), 16 | sample3 = 10; 17 | sample1.print(); 18 | sample2.print(); 19 | sample3.print(); 20 | /*Sample sample4{10}; // c++11 21 | sample4.print();*/ 22 | Sample array1[] = {10, -5, 0, 127}; 23 | std::cout << "array1[]" << std::endl; 24 | for (size_t i = 0; i < sizeof(array1) / sizeof(*array1); ++i) { 25 | array1[i].print(); 26 | } 27 | const int N = 5; 28 | Sample array2[N] = { 29 | Sample(10, 0.1), 30 | Sample(-5, -3.6), 31 | Sample(0, 0.0), 32 | Sample() // default constructor 33 | }; 34 | std::cout << "array2[" << N << "]" << std::endl; 35 | for (int i = 0; i < N; ++i) { 36 | array2[i].print(); 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /examples/lecture1/013_insecure_count_limit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // for strlcpy. Prior to run on should run install libbsd-dev package on Ubuntu like OS, and run with -lbsd flag 5 | 6 | #define MAX_STR_LEN 80 7 | 8 | void foo(char *s) { 9 | char *local = (char *)malloc((MAX_STR_LEN + 1) * sizeof(char)); 10 | if (!local) { 11 | return; 12 | } 13 | // NON-COMPLIANT 14 | //strcpy(local, s); 15 | //sprintf(local, "%s", s); 16 | 17 | // COMPLIANT 18 | //snprintf(local, MAX_STR_LEN, "%s", s); 19 | //strlcpy(local, s, MAX_STR_LEN); 20 | strncpy(local, s, MAX_STR_LEN); 21 | local[MAX_STR_LEN] = '\0'; 22 | printf("From foo: %s\n", local); 23 | free(local); 24 | } 25 | 26 | int main(int argc, char *argv[]) { 27 | int N = 100; 28 | char *s = (char *)malloc((N + 1) * sizeof(char)); 29 | if (!s) { 30 | return 0; 31 | } 32 | for (size_t i = 0; i < N; ++i) { 33 | s[i] = 'A'; 34 | } 35 | s[N] = '\0'; 36 | printf("From main: %s\n", s); 37 | foo(s); 38 | free(s); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /2017_2/examples/stl/041_equality_equivalent.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | struct A { 14 | public: 15 | A(const std::string &s) : tmp(s){}; 16 | 17 | bool operator<(const A &rhs) const { 18 | std::cout << "< called this " << tmp << " rhs = " << rhs.tmp << endl; 19 | return tmp < rhs.tmp; 20 | } 21 | 22 | bool operator==(const A &rhs) const { 23 | std::cout << " == called this " << tmp << " rhs = " << rhs.tmp << endl; 24 | return tmp == rhs.tmp; 25 | } 26 | std::string tmp; 27 | }; 28 | 29 | int main() { 30 | std::set s; 31 | s.insert(A("1")); // empty 32 | 33 | 34 | s.insert(A("2")); 35 | // s.insert(A("3")); 36 | 37 | std::cout << "---\n"; 38 | auto it = s.find(A("2")); 39 | std::cout << "---\n"; 40 | if (it != s.end()) 41 | std::cout << "2 has found\n"; 42 | 43 | it = std::find(s.begin(), s.end(), A("2")); 44 | if (it != s.end()) 45 | std::cout << "2 has found\n"; 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /examples/c_homework/test_input: -------------------------------------------------------------------------------- 1 | "Здесь должно быть \"название\" команды" 2 | "Здесь должно быть \"название\" проекта" 3 | "Здесь должно быть \"описание\" проекта" 4 | "Здесь должен быть \"размер команды\": \"3\" или \"4\"" 5 | 3 6 | "Здесь должно быть \"имя первого члена команды\"" 7 | "Здесь должна быть \"фамилия первого члена команды\"" 8 | "Тут должен быть \"номер трека\":\"1\" или \"2\"" 9 | 1 10 | "Здесь должна быть \"группа первого члена команды\": \"1\", \"2\" или \"3\"" 11 | 2 12 | github.com/first_member 13 | "Здесь должно быть \"имя второго члена команды\"" 14 | "Здесь должна быть \"фамилия второго члена команды\"" 15 | "Тут должен быть \"номер трека\":\"1\" или \"2\"" 16 | 2 17 | "Здесь должна быть \"группа второго члена команды\": \"1\", \"2\" или \"3\"" 18 | 1 19 | http://github.com/second_member 20 | "Здесь должно быть \"имя третьего члена команды\"" 21 | "Здесь должна быть \"фамилия третьего члена команды\"" 22 | "Тут должен быть \"номер трека\":\"1\" или \"2\"" 23 | 2 24 | "Здесь должна быть \"группа третьего члена команды\": \"1\", \"2\" или \"3\"" 25 | 3 26 | https://github.com/last_member 27 | 2 28 | 29 | -------------------------------------------------------------------------------- /examples/lecture2/006_simple_waitpid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | int pid, status; 9 | pid = fork(); 10 | 11 | if (pid == 0) { 12 | sleep(2); 13 | exit(EXIT_SUCCESS); 14 | } 15 | 16 | printf("Forked with pid %d\n", pid); 17 | 18 | do { 19 | pid_t waited_pid = waitpid(pid, &status, WNOHANG); 20 | 21 | printf("Got waited_pid=%d, status %d\n", waited_pid, status); 22 | 23 | if (waited_pid < 0) { 24 | printf("waitpid error %d\n", waited_pid); 25 | break; 26 | } 27 | 28 | if (waited_pid) { 29 | if (WIFEXITED(status)) { 30 | printf("Exited with code %d\n", WEXITSTATUS(status)); 31 | } 32 | else if (WIFSIGNALED(status)) { 33 | printf("Killed by signal %d\n", WTERMSIG(status)); 34 | } 35 | else if (WIFSTOPPED(status)) { 36 | printf("Stopped by signal %d\n", WSTOPSIG(status)); 37 | } 38 | break; 39 | } 40 | 41 | sleep(1); 42 | } while (1); 43 | } -------------------------------------------------------------------------------- /examples/lecture3/001_encapsulation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A { 4 | int a; 5 | private: 6 | int b; 7 | public: 8 | int c; 9 | void print() { 10 | std::cout << "A: " << a << " " << b << " " << c << std::endl; 11 | } 12 | }; 13 | 14 | struct B { 15 | int a; 16 | private: 17 | int b; 18 | public: 19 | int c; 20 | void print() { 21 | std::cout << "B: " << a << " " << b << " " << c << std::endl; 22 | } 23 | }; 24 | 25 | union C { 26 | int a; 27 | private: 28 | int b; 29 | public: 30 | int c; 31 | void print() { 32 | std::cout << "C: " << a << " " << b << " " << c << std::endl; 33 | } 34 | }; 35 | 36 | int main(int argc, char *argv[]) { 37 | A a; 38 | a.print(); 39 | /*a.a = 1; 40 | a.print();*/ 41 | /*a.b = 2; 42 | a.print();*/ 43 | a.c = 3; 44 | a.print(); 45 | B b; 46 | b.print(); 47 | b.a = 1; 48 | b.print(); 49 | /*b.b = 2; 50 | b.print();*/ 51 | b.c = 3; 52 | b.print(); 53 | C c; 54 | c.print(); 55 | c.a = 1; 56 | c.print(); 57 | /*c.b = 2; 58 | c.print();*/ 59 | c.c = 3; 60 | c.print(); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /examples/lecture2/003_file_io.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | struct book { 5 | char name[20]; 6 | size_t pages_count; 7 | } my_book = { "Tutorial", 100 }; 8 | 9 | static const char *file_name = "books"; 10 | 11 | // Write to file 12 | FILE *f = fopen(file_name, "wb"); 13 | 14 | if (!f) { 15 | fprintf(stderr, "Failed to open file for write\n"); 16 | return 1; 17 | } 18 | 19 | if (fwrite(&my_book, sizeof(struct book), 1, f) != 1) { 20 | fprintf(stderr, "Failed to write struct into file\n"); 21 | // Intentional no return to close file 22 | } 23 | 24 | if (fclose(f)) { 25 | fprintf(stderr, "Failed to close file\n"); 26 | return 1; 27 | } 28 | 29 | // Reading file 30 | if ((f = fopen(file_name, "rb")) == NULL) { 31 | fprintf(stderr, "Failed to open file for read\n"); 32 | return 1; 33 | } 34 | 35 | while (!feof(f)) { 36 | if (fread(&my_book, sizeof(struct book), 1, f) == 1) { 37 | printf("Book %s (%ld pages)\n", my_book.name, my_book.pages_count); 38 | } 39 | } 40 | 41 | if (fclose(f)) { 42 | fprintf(stderr, "Failed to close file\n"); 43 | return 1; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /2017_2/examples/stl/035_vector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct A { 6 | std::string param1; 7 | int param2; 8 | 9 | A(std::string p_name, int p_year) 10 | : param1(std::move(p_name)), param2(p_year) { 11 | std::cout << "I am being constructed.\n"; 12 | } 13 | 14 | A(A &&other) : param1(std::move(other.param1)), param2(other.param2) { 15 | std::cout << "I am being moved.\n"; 16 | } 17 | 18 | A(const A &other) : param1(other.param1), param2(other.param2) { 19 | std::cout << "I am being copied.\n"; 20 | } 21 | 22 | A &operator=(const A &other) = default; 23 | }; 24 | 25 | // -------------------------------- 26 | int main() { 27 | std::vector my_magic_vector; 28 | A some_a("test", 1); 29 | my_magic_vector.reserve(10); 30 | 31 | std::cout << "\nemplace_back:\n"; 32 | my_magic_vector.emplace_back("String1", 1000); 33 | std::cout << "----\n"; 34 | my_magic_vector.emplace_back(A("String1", 1000)); 35 | 36 | std::cout << "\npush_back:\n"; 37 | my_magic_vector.push_back(A("String2", 2000)); 38 | //my_magic_vector2.push_back("String2", 2000); error 39 | 40 | std::cout << "\nappending existing object:\n"; 41 | my_magic_vector.emplace_back(some_a); 42 | my_magic_vector.push_back(some_a); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /2017_2/examples/stl/036_vector_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct A { 7 | std::string param1; 8 | int param2; 9 | 10 | A(std::string p_name, int p_year) 11 | : param1(std::move(p_name)), param2(p_year) { 12 | std::cout << "I am being constructed.\n"; 13 | } 14 | 15 | A(A &&other) : param1(std::move(other.param1)), param2(other.param2) { 16 | std::cout << "I am being moved.\n"; 17 | } 18 | 19 | A(const A &other) : param1(other.param1), param2(other.param2) { 20 | std::cout << "I am being copied.\n"; 21 | } 22 | 23 | A &operator=(const A &other) = default; 24 | }; 25 | 26 | // -------------------------------- 27 | int main() { 28 | A some_a("test", 1); 29 | std::vector v; 30 | 31 | v.reserve(2); 32 | assert(v.capacity() == 2); 33 | 34 | v[0] = some_a; 35 | v[1] = some_a; 36 | 37 | for(decltype(v)::iterator it = v.begin(); it < v.end(); it++) { 38 | std::cout << (*it).param1; 39 | } 40 | 41 | std::cout << v[0].param1; 42 | v.reserve(100); 43 | assert(v.capacity() == 100); 44 | std::cout << v[0].param1; 45 | 46 | v[2] = some_a; 47 | v[3] = some_a; 48 | 49 | for(auto it = v.begin(); it < v.end(); it++) { 50 | std::cout << (*it).param1; 51 | } 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /examples/lecture3/015_move_assignment.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Beta { 4 | Beta(std::string s) : msg(s) { 5 | std::cout << "Beta(std::string)" << std::endl; 6 | } 7 | Beta() { 8 | std::cout << "Beta()" << std::endl; 9 | } 10 | Beta(const Beta &b) { 11 | std::cout << "Beta(const Beta&)" << std::endl; 12 | } 13 | Beta(Beta &&b) { 14 | std::cout << "Beta(Beta &&b)" << std::endl; 15 | } 16 | /* Try only this implementation instead of two next 17 | Beta &operator=(Beta rhs) { 18 | std::cout << "operator=(Beta)" << std::endl; 19 | msg = std::move(rhs.msg); 20 | return *this; 21 | }*/ 22 | Beta &operator=(Beta const &b) { 23 | std::cout << "operator=(Beta const &)" << std::endl; 24 | this->msg = b.msg; 25 | return *this; 26 | } 27 | Beta &operator=(Beta &&rhs) { 28 | std::cout << "operator=(Beta &&)" << std::endl; 29 | msg = std::move(rhs.msg); 30 | return *this; 31 | } 32 | std::string msg; 33 | }; 34 | 35 | int main(int argc, char *argv[]) { 36 | Beta beta{"Per aspera ad astra"}, gamma; 37 | gamma = beta; 38 | gamma = std::move(beta); 39 | std::cout << gamma.msg << std::endl 40 | << beta.msg << std::endl; 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /examples/lecture3/021_RAII.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool cond() { 6 | return rand() % 2 == 0; 7 | } 8 | 9 | void logic(const char *s) {} 10 | 11 | void bad() { 12 | std::cout << "ALLOCATION" << std::endl; 13 | char *str = new char[10]; 14 | if (cond()) { 15 | std::cout << "EMERGENCY RETURN" << std::endl; 16 | std::cout << "LEAK :-(" << std::endl; 17 | return; 18 | } 19 | logic(str); 20 | std::cout << "CLEANING" << std::endl; 21 | delete []str; 22 | } 23 | 24 | class RAII_str { 25 | private: 26 | char *str; 27 | public: 28 | RAII_str(char *str) : str(str) { 29 | std::cout << "ALLOCATION" << std::endl; 30 | std::cout << "RAII_str()" << std::endl; 31 | } 32 | 33 | ~RAII_str() { 34 | std::cout << "~RAII_str()" << std::endl; 35 | std::cout << "CLEANING" << std::endl; 36 | delete []str; 37 | } 38 | 39 | const char *getStr() { 40 | return str; 41 | } 42 | }; 43 | 44 | void good() { 45 | RAII_str r(new char[10]); 46 | if (cond()) { 47 | std::cout << "EMERGENCY RETURN" << std::endl; 48 | return; 49 | } 50 | logic(r.getStr()); 51 | } 52 | 53 | int main(int argc, char *argv[]) { 54 | srand(time(NULL)); 55 | bad(); 56 | good(); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /examples/lecture2/009_mmap_shared_memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | size_t page_size = getpagesize(); 10 | 11 | char *shared_memory = mmap(NULL, page_size, PROT_READ | PROT_WRITE, 12 | MAP_SHARED | MAP_ANONYMOUS, -1, 0); 13 | 14 | if (!shared_memory) { 15 | printf("Failed to map\n"); 16 | return 1; 17 | } 18 | 19 | int v = 0; 20 | *shared_memory = 0; 21 | 22 | pid_t pid = fork(); 23 | 24 | if (pid == -1) { 25 | printf("Fork failed\n"); 26 | if (munmap(shared_memory, page_size)) { 27 | printf("Failed to unmap\n"); 28 | } 29 | return 1; 30 | } 31 | 32 | if (pid == 0) { 33 | *shared_memory = 42; 34 | v = 50; 35 | } else { 36 | pid_t wait_result = wait(NULL); 37 | if (wait_result != pid) { 38 | printf("Wait failed with code %d\n", wait_result); 39 | } 40 | } 41 | 42 | if (pid == 0) { 43 | printf("CHILD: Shared %d, not shared %d\n", *shared_memory, v); 44 | } else { 45 | printf("PARENT: Shared %d, not shared %d\n", *shared_memory, v); 46 | } 47 | 48 | if (pid) { 49 | if (munmap(shared_memory, page_size)) { 50 | printf("Failed to unmap\n"); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /examples/lecture3/009_transform_constuctors_and_operations.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct Sample { 7 | private: 8 | int int_prm; 9 | double dbl_prm; 10 | public: 11 | // transformation constructors 12 | Sample(const char *s) { 13 | int_prm = strlen(s); 14 | dbl_prm = std::time(NULL); 15 | std::cout << "Sample(const char *s)" << std::endl; 16 | } 17 | Sample(const std::string &s) { 18 | int_prm = s.length(); 19 | dbl_prm = std::time(NULL); 20 | std::cout << "Sample(std::string &s)" << std::endl; 21 | } 22 | // transformation operations 23 | operator int() { 24 | std::cout << "int()" << std::endl; 25 | return int_prm; 26 | } 27 | operator double() { 28 | std::cout << "double()" << std::endl; 29 | return dbl_prm; 30 | } 31 | 32 | operator char *() { 33 | std::cout << "char *()" << std::endl; 34 | std::time_t time = double(*this); 35 | return std::asctime(std::localtime(&time)); 36 | } 37 | }; 38 | 39 | int main(int argc, char *argv[]) { 40 | const char *s = "Hello"; 41 | std::string ss(s); 42 | Sample s1(s); 43 | Sample s2(ss); 44 | int len = s1; 45 | for (int i = 0; i < len; ++i) { 46 | std::cout << s[i]; 47 | } 48 | std::cout << std::endl; 49 | std::cout << (char *)s2 << std::endl; 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /examples/lecture2/016_mutex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct { 5 | pthread_mutex_t mutex; // mutex for value protection 6 | int value; // protected value 7 | } data_t; 8 | 9 | // common object; mutex is initialized statically 10 | data_t data = {PTHREAD_MUTEX_INITIALIZER, 0}; 11 | 12 | void *thread_routine(void *arg) { 13 | pthread_mutex_t *mutex = &data.mutex; 14 | int errflag = 0; 15 | // lock mutex before value change 16 | errflag = pthread_mutex_lock(mutex); 17 | // check if pthread_mutex_lock call was successful 18 | if (errflag != 0) { 19 | // ... 20 | } 21 | data.value += 1; // change value 22 | // unlock mutex after value change 23 | errflag = pthread_mutex_unlock(mutex); 24 | // check if pthread_mutex_unlock call was successful 25 | if (errflag != 0) { 26 | // ... 27 | } 28 | return arg; 29 | } 30 | 31 | int main(int argc, char *argv[]) { 32 | const int N = 10000; 33 | pthread_t threadIds[N]; 34 | for (int i = 0; i < N; i++) { 35 | int errflag = pthread_create(&threadIds[i], NULL, thread_routine, NULL); 36 | if (errflag != 0) { 37 | // ... 38 | } 39 | } 40 | for (int i = 0; i < N; i++) { 41 | int errflag = pthread_join(threadIds[i], NULL); 42 | if (errflag != 0) { 43 | // ... 44 | } 45 | } 46 | printf("result value: %d\n", data.value); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /examples/lecture3/013_simple_initializers_in_cpp11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int counter = int(); 4 | 5 | struct Sample { 6 | std::string msg{"Abeunt studia in mores"}; 7 | int id = ++counter; 8 | int n{42}; 9 | 10 | static const std::size_t sz = sizeof n; 11 | Sample() { 12 | std::cout << "Sample()" << std::endl; 13 | } 14 | Sample(int _n) : n(_n) { 15 | std::cout << "Sample(int)" << std::endl; 16 | } 17 | Sample(const Sample &s) { 18 | std::cout << "Sample(const Sample &s)" << std::endl; 19 | } 20 | void print() { 21 | std::cout << id << " " << n << " " << msg << std::endl; 22 | } 23 | }; 24 | 25 | struct Coord3D { 26 | private: 27 | int coords[3]; 28 | public: 29 | Coord3D(std::initializer_list l) { 30 | std::cout << "Coord3D(std::initializer_list)" << std::endl; 31 | std::copy(l.begin(), l.end(), coords); 32 | } 33 | 34 | void print() { 35 | std::cout << coords[0] << " " << coords[1] << " " << coords[2] << std::endl; 36 | } 37 | }; 38 | 39 | int main() { 40 | Sample s1; 41 | Sample s2(10); 42 | Sample s3 = {1}; 43 | Sample s4{2}; 44 | Sample s5{s4}; 45 | s1.print(); 46 | s2.print(); 47 | s3.print(); 48 | s4.print(); 49 | s5.print(); 50 | Coord3D a = {1, 2, 3}; 51 | Coord3D b{4, 5, 6}; 52 | Coord3D c{a}; 53 | a.print(); 54 | b.print(); 55 | c.print(); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /examples/lecture2/021_semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | sem_t semaphore; 9 | 10 | void *thread_func(void *arg) { 11 | int id = (int)arg; 12 | for (int i = 0; i < 3; ++i) { 13 | printf("THREAD #%d: Waiting semaphore (i = %d)...\n", id, i); 14 | sem_wait(&semaphore); 15 | printf("THREAD #%d: Hello (i = %d)\n", id, i); 16 | sleep(2); 17 | sem_post(&semaphore); 18 | printf("THREAD #%d: Leaving critical area (i = %d)...\n", id, i); 19 | sleep(2); 20 | } 21 | printf("THREAD #%d: Finished work!\n", id); 22 | return arg; 23 | } 24 | 25 | int main(int argc, char *argv[]) { 26 | const int threads_count = 3; 27 | // Инициализация семафора: 28 | // первый параметр = 0 => семафор используется между тредами процесса и доступен всем тредам 29 | // второй параметр - лимит одновременно находящихся в критической зоне тредов 30 | pthread_t threads[threads_count]; 31 | sem_init(&semaphore, 0, 1); 32 | 33 | for (int i = 0; i < threads_count; ++i) { 34 | printf("Starting thread #%d\n", i); 35 | pthread_create(&threads[i], NULL, thread_func, (void *)i); 36 | } 37 | 38 | for (int i = 0; i < threads_count; ++i) { 39 | void *result = NULL; 40 | pthread_join(threads[i], &result); 41 | printf("Registered end of thread #%d\n", (int)result); 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /examples/lecture2/008_mmaped_file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | static const char *filename = "mapped_file"; 11 | char replacing_symbol = 'A'; 12 | 13 | /* 14 | FILE *f = fopen(filename, "r"); 15 | int fd = fileno(f); 16 | */ 17 | int fd = open(filename, O_RDONLY); // или O_RDWR 18 | struct stat st; 19 | stat(filename, &st); 20 | 21 | size_t file_size = st.st_size; 22 | 23 | // PROT_READ - чтение; PROT_WRITE - чтение/запись 24 | // MAP_PRIVATE - не записывать в файл; 25 | // MAP_POPULATE - предзагрузка файла ядром; 26 | // MAP_SHARED - деление с другими процессами 27 | char *region = mmap(NULL, 28 | file_size, 29 | PROT_READ | PROT_WRITE, 30 | MAP_PRIVATE | MAP_POPULATE, 31 | fd, 32 | 0); 33 | if (region == MAP_FAILED) { 34 | printf("mmap failed\n"); 35 | close(fd); 36 | return 1; 37 | } 38 | 39 | printf("What was read\n"); 40 | write(fileno(stdout), region, file_size); // fileno(stdout) == 1 41 | 42 | for (size_t i = 0; i < file_size; ++i) { region[i] = replacing_symbol; } 43 | 44 | printf("After modification: %s\n", region); 45 | 46 | if (munmap(region, file_size) != 0) { 47 | printf("munmap failed\n"); 48 | } 49 | 50 | close(fd); 51 | } -------------------------------------------------------------------------------- /examples/lecture2/015_thread_routine.c: -------------------------------------------------------------------------------- 1 | #include // EXIT_SUCCESS 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define MAX_SLEEP_TIME 5 8 | 9 | void rand_sleep(char *whoami) { 10 | int sleep_time = 1 + rand() % MAX_SLEEP_TIME; 11 | printf("%s: sleeping for %d seconds...\n", whoami, sleep_time); 12 | sleep(sleep_time); 13 | } 14 | 15 | void *thread_routine(void *arg) { 16 | int errflag = 0; 17 | // ... 18 | // detach from main process as a POSIX thread until the end 19 | errflag = pthread_detach(pthread_self()); 20 | // check if pthread_detach() call was successful 21 | if (errflag != 0) { 22 | printf("Thread: caught error: %d\n", errflag); 23 | } 24 | rand_sleep("Thread"); 25 | printf("Thread: hello!\n"); 26 | // gracefully exit thread with void *value as a result 27 | return arg; // another variant: return NULL etc 28 | } 29 | 30 | int main(int argc, char *argv[]) { 31 | srand(time(NULL)); 32 | int errflag = 0; 33 | pthread_t thread; // thread id 34 | 35 | // create and tun POSIX thread 36 | errflag = pthread_create(&thread, NULL, thread_routine, NULL); 37 | // check if thread_create call was successful 38 | if (errflag != 0) { 39 | printf("Main: caught error: %d\n", errflag); 40 | } 41 | rand_sleep("Main"); 42 | printf("Main: thread id: %ld\n", thread); 43 | // pthread_exit(0); 44 | // gracefully exit main thread and associated process 45 | return EXIT_SUCCESS; 46 | } 47 | -------------------------------------------------------------------------------- /examples/lecture3/011_destructors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A { 4 | public: 5 | A() { 6 | std::cout << "A()" << std::endl; 7 | } 8 | A(const A &a) { 9 | std::cout << "A(const &a)" << std::endl; 10 | } 11 | A &operator=(A &a) { 12 | std::cout << "A &operator=(A &a)" << std::endl; 13 | return a; 14 | } 15 | ~A() { 16 | std::cout << "~A()" << std::endl; 17 | } 18 | }; 19 | 20 | class B { 21 | public: 22 | B() { 23 | std::cout << "B()" << std::endl; 24 | } 25 | B(const B &b) { 26 | std::cout << "B(const &b)" << std::endl; 27 | } 28 | B &operator=(B &b) { 29 | std::cout << "B &operator=(B &b)" << std::endl; 30 | return b; 31 | } 32 | ~B() { 33 | std::cout << "~B()" << std::endl; 34 | } 35 | }; 36 | 37 | class C { 38 | private: 39 | A a; 40 | B b; 41 | public: 42 | C(A &a, B &b) : a(a), b(b) {} 43 | ~C() { 44 | std::cout << "~C()" << std::endl; 45 | } 46 | }; 47 | 48 | int main(int argc, char *argv[]) { 49 | A a; 50 | B b; 51 | std::cout << "C(a, b)" << std::endl; 52 | C c(a, b); 53 | C *pc; 54 | { 55 | std::cout << "C(a, b)" << std::endl; 56 | C c(a, b); 57 | std::cout << "C(a, b)" << std::endl; 58 | pc = new C(a, b); 59 | std::cout << "end of scope" << std::endl; 60 | } 61 | std::cout << "destructor call" << std::endl; 62 | delete pc; 63 | std::cout << "end of scope" << std::endl; 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /examples/lecture1/015_double_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | char *get_new_s(char *s) { 7 | char *new_s = (char *)malloc((strlen(s) + 1) * sizeof(char)); 8 | strcpy(new_s, s); 9 | new_s[0] = s[0] > 'a' && s[0] < 'z' ? s[0] - 'a' + 'A' : s[0]; 10 | free(s); 11 | return new_s; 12 | } 13 | 14 | int main(int argc, char *argv[]) { 15 | int *null_p = NULL; 16 | free(null_p); // It's ok, no error 17 | free(null_p); // It's ok, no error 18 | 19 | /* Example 1 */ 20 | char *s = (char *)malloc((10 + 1) * sizeof(char)); 21 | if (!s) { 22 | return 0; 23 | } 24 | scanf("%10s", s); 25 | char *new_s = get_new_s(s); 26 | free(new_s); 27 | //free(s); 28 | 29 | /* Example 2 */ 30 | char *a = (char *)malloc(10 * sizeof(char)); 31 | if (a) { 32 | char *b = realloc(a, 100); 33 | if (b) { 34 | //free(a); 35 | free(b); 36 | } 37 | } 38 | 39 | /* Example 3 */ 40 | char *s1 = (char *)malloc(10 * sizeof(char)); 41 | if (!s1) { 42 | return 0; 43 | } 44 | char *s2 = (char *)malloc(20 * sizeof(char)); 45 | if (!s2) { 46 | free(s1); 47 | // return 0; // forgot to return.. 48 | } 49 | else { 50 | /* ... */ 51 | } 52 | if ((uint64_t)s2 % 128 != 0) { // for some reason 53 | free(s2); 54 | } 55 | else { 56 | /* ... */ 57 | } 58 | 59 | free(s1); 60 | free(s2); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /examples/lecture2/025_aligned.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef int __attribute__((aligned(256))) al256int_t; 5 | 6 | uint64_t global_simple_var; 7 | uint64_t global_aligned_var __attribute__((aligned(128))); 8 | al256int_t global_typed_aligned_var; 9 | 10 | void print_align_results(uint64_t *simple_var, uint64_t *aligned_var, al256int_t *typed_aligned_var) { 11 | printf("simple: %p, sizeof: %ld, modulus to 128: %ld\n", simple_var, sizeof *simple_var, (uint64_t)simple_var % 128); 12 | printf("aligned: %p, sizeof: %ld, modulus to 128: %ld\n", aligned_var, sizeof *aligned_var, (uint64_t)aligned_var % 128); 13 | printf("typed aligned: %p, sizeof: %ld, modulus to 256: %ld\n", typed_aligned_var, sizeof *typed_aligned_var, (uint64_t)typed_aligned_var % 256); 14 | } 15 | 16 | int main(int argc, char *argv[]) { 17 | uint64_t simple_var; 18 | uint64_t aligned_var __attribute__((aligned(128))); 19 | al256int_t typed_aligned_var; 20 | 21 | static uint64_t static_simple_var; 22 | static uint64_t static_aligned_var __attribute__((aligned(128))); 23 | static al256int_t static_typed_aligned_var; 24 | 25 | printf("global variables:\n"); 26 | print_align_results(&global_simple_var, &global_aligned_var, &global_typed_aligned_var); 27 | 28 | printf("stack variables:\n"); 29 | print_align_results(&simple_var, &aligned_var, &typed_aligned_var); 30 | 31 | printf("static variables:\n"); 32 | print_align_results(&static_simple_var, &static_aligned_var, &static_typed_aligned_var); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /examples/lecture2/010_pipe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MAX_LEN 80 7 | 8 | int main() { 9 | char str[] = "Simple string\n"; 10 | char buf[MAX_LEN]; 11 | 12 | int fd[2]; 13 | // fd[0] - reading 14 | // fd[1] - writing 15 | 16 | if (pipe(fd) != 0) { 17 | printf("Opening pipe failed\n"); 18 | return 1; 19 | } 20 | 21 | pid_t pid = fork(); 22 | if (pid == -1) { 23 | printf("Fork failed\n"); 24 | if (close(fd[0])) { 25 | printf("Failed to close read pipe\n"); 26 | } 27 | if (close(fd[1])) { 28 | printf("Failed to close write pipe\n"); 29 | } 30 | return 1; 31 | } 32 | 33 | if (pid == 0) { 34 | if (close(fd[0])) { 35 | printf("CHILD: Failed to close read pipe\n"); 36 | } 37 | if (write(fd[1], str, strlen(str) + 1) == -1) { 38 | printf("CHILD: Failed to write into pipe\n"); 39 | } 40 | if (close(fd[1])) { 41 | printf("CHILD: Failed to close write pipe\n"); 42 | } 43 | exit(0); 44 | } 45 | 46 | if (close(fd[1])) { 47 | printf("PARENT: Failed to close write pipe\n"); 48 | } 49 | if (read(fd[0], buf, sizeof(buf)) < 0) { 50 | printf("PARENT: Failed to read from pipe\n"); 51 | } else { 52 | printf("PARENT: Received from child: %s\n", buf); 53 | } 54 | if (close(fd[0])) { 55 | printf("PARENT: Failed to close read pipe\n"); 56 | } 57 | } -------------------------------------------------------------------------------- /examples/lecture1/011_c11_generics.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define typename(x) _Generic((x), /* Get the name of a type */ \ 6 | \ 7 | _Bool: "_Bool", unsigned char: "unsigned char", \ 8 | char: "char", signed char: "signed char", \ 9 | short int: "short int", unsigned short int: "unsigned short int", \ 10 | int: "int", unsigned int: "unsigned int", \ 11 | long int: "long int", unsigned long int: "unsigned long int", \ 12 | long long int: "long long int", unsigned long long int: "unsigned long long int", \ 13 | float: "float", double: "double", \ 14 | long double: "long double", char *: "pointer to char", \ 15 | void *: "pointer to void", int *: "pointer to int", \ 16 | default: "other") 17 | 18 | #define fmt "%20s is '%s'\n" 19 | int main() { 20 | 21 | size_t s; ptrdiff_t p; intmax_t i; int ai[3] = {0}; 22 | printf( fmt fmt fmt fmt fmt fmt fmt fmt, 23 | 24 | "size_t", typename(s), "ptrdiff_t", typename(p), 25 | "intmax_t", typename(i), "character constant", typename('0'), 26 | "0x7FFFFFFF", typename(0x7FFFFFFF), "0xFFFFFFFF", typename(0xFFFFFFFF), 27 | "0x7FFFFFFFU", typename(0x7FFFFFFFU), "array of int", typename(ai)); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /2017_2/examples/stl/037_vector_3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | // -------------------------------- 13 | class Date { 14 | public: 15 | Date() = default; 16 | explicit Date(const std::string &str){}; 17 | Date(const Date &rhs){}; 18 | 19 | Date &operator=(const std::string &rhs) { return *this; } 20 | bool operator==(const std::string &rhs) { return true; } 21 | 22 | friend ostream &operator<<(ostream &out, const Date &c) { 23 | cout << "Date\n"; 24 | return out; 25 | }; 26 | 27 | friend istream &operator>>(istream &in, Date &c) { 28 | cout << "Date: \n"; 29 | in >> c.date; 30 | return in; 31 | } 32 | 33 | static Date TodaysDate() { return Date("29/04/19"); } 34 | string date; 35 | }; 36 | 37 | int main() { 38 | // std::binary_function 39 | std::stack s; // deque as default 40 | std::queue q; // deque as default 41 | std::priority_queue pq; // vector as default 42 | 43 | // std::find_if 44 | vector e; 45 | copy(istream_iterator(cin), istream_iterator(), back_inserter(e)); 46 | vector::iterator first = find(e.begin(), e.end(), "01/01/95"); 47 | vector::iterator last = find(e.begin(), e.end(), "12/31/95"); 48 | *last = "12/30/95"; 49 | copy(first, last, ostream_iterator(cout, "\n")); 50 | e.insert(--e.end(), Date::TodaysDate()); 51 | copy(first, last, ostream_iterator(cout, "\n")); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/033_observer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | struct Observer; 8 | 9 | struct Model { 10 | virtual ~Model() { 11 | observers_.clear(); 12 | }; 13 | 14 | void AddObserver(Observer* observer) { 15 | observers_.push_back(observer); 16 | } 17 | 18 | void RemoveObserver(Observer* observer) { 19 | observers_.remove(observer); 20 | } 21 | 22 | void SetData(int new_data) { 23 | // store data 24 | Notify(); 25 | } 26 | 27 | void Notify(); 28 | 29 | std::list observers_; 30 | }; 31 | 32 | 33 | struct Observer { 34 | virtual void OnModelChanched() = 0; 35 | }; 36 | 37 | struct ConcreteObserver1 : public Observer { 38 | void OnModelChanched() override { 39 | std::cout << "hello from model 1\n"; 40 | } 41 | }; 42 | 43 | struct ConcreteObserver2 : public Observer { 44 | void OnModelChanched() override { 45 | std::cout << "hello from model 2\n"; 46 | } 47 | }; 48 | 49 | struct ConcreteObserver3 : public Observer { 50 | void OnModelChanched() override { 51 | std::cout << "hello from model 3\n"; 52 | } 53 | }; 54 | 55 | void Model::Notify() { 56 | for(auto observer: observers_) 57 | observer->OnModelChanched(); 58 | } 59 | 60 | int main() { 61 | Model model; 62 | 63 | Observer* observer1 = new ConcreteObserver1(); 64 | Observer* observer2 = new ConcreteObserver2(); 65 | Observer* observer3 = new ConcreteObserver3(); 66 | 67 | model.AddObserver(observer1); 68 | model.AddObserver(observer2); 69 | model.AddObserver(observer3); 70 | 71 | model.SetData(5); 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /2017_2/examples/patterns/033_observer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | struct Observer; 8 | 9 | struct Model { 10 | virtual ~Model() { 11 | observers_.clear(); 12 | }; 13 | 14 | void AddObserver(Observer* observer) { 15 | observers_.push_back(observer); 16 | } 17 | 18 | void RemoveObserver(Observer* observer) { 19 | observers_.remove(observer); 20 | } 21 | 22 | void SetData(int new_data) { 23 | // store data 24 | Notify(); 25 | } 26 | 27 | void Notify(); 28 | 29 | std::list observers_; 30 | }; 31 | 32 | 33 | struct Observer { 34 | virtual void OnModelChanched() = 0; 35 | }; 36 | 37 | struct ConcreteObserver1 : public Observer { 38 | void OnModelChanched() override { 39 | std::cout << "hello from model 1\n"; 40 | } 41 | }; 42 | 43 | struct ConcreteObserver2 : public Observer { 44 | void OnModelChanched() override { 45 | std::cout << "hello from model 2\n"; 46 | } 47 | }; 48 | 49 | struct ConcreteObserver3 : public Observer { 50 | void OnModelChanched() override { 51 | std::cout << "hello from model 3\n"; 52 | } 53 | }; 54 | 55 | void Model::Notify() { 56 | for(auto observer: observers_) 57 | observer->OnModelChanched(); 58 | } 59 | 60 | int main() { 61 | Model model; 62 | 63 | Observer* observer1 = new ConcreteObserver1(); 64 | Observer* observer2 = new ConcreteObserver2(); 65 | Observer* observer3 = new ConcreteObserver3(); 66 | 67 | model.AddObserver(observer1); 68 | model.AddObserver(observer2); 69 | model.AddObserver(observer3); 70 | 71 | model.SetData(5); 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/030_adapter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct XmlReader { 5 | virtual std::string read() { return "<>\n"; } 6 | }; 7 | 8 | struct JsonReader { 9 | std::string fecthJson() { return "{}\n"; } 10 | }; 11 | 12 | struct Presentaion { 13 | void Show(XmlReader *reader) { 14 | std::cout << reader->read(); /*do something with reader*/ 15 | } 16 | }; 17 | 18 | // composition adapter 19 | struct JsonToXmlAdapter : public XmlReader { 20 | JsonToXmlAdapter(JsonReader *json_reader) : json_reader_(json_reader) {} 21 | 22 | std::string read() override { 23 | std::cout << json_reader_->fecthJson(); 24 | return "<>\n"; 25 | } 26 | 27 | private: 28 | JsonReader *json_reader_; 29 | }; 30 | 31 | // class adapter 32 | struct JsonToXmlAdapterClass : public XmlReader, public JsonReader { 33 | std::string read() override { 34 | std::cout << JsonReader::fecthJson(); 35 | return "<>\n"; 36 | } 37 | }; 38 | 39 | int main() { 40 | Presentaion p; 41 | XmlReader *xml_reader = new XmlReader; 42 | p.Show(xml_reader); 43 | 44 | 45 | JsonReader *json_reader = new JsonReader; 46 | // p.Show(json_reader); // недопустимо 47 | 48 | { 49 | // composition adaptor 50 | std::cout << "composition: \n"; 51 | JsonToXmlAdapter* json_to_xml_adater = new JsonToXmlAdapter(json_reader); 52 | p.Show(json_to_xml_adater); 53 | } 54 | 55 | { 56 | // class adaptor 57 | std::cout << "class: \n"; 58 | JsonToXmlAdapterClass* json_to_xml_adater = new JsonToXmlAdapterClass; 59 | p.Show(json_to_xml_adater); 60 | } 61 | 62 | std::stack s; 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /2017_2/examples/patterns/030_adapter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct XmlReader { 5 | virtual std::string read() { return "<>\n"; } 6 | }; 7 | 8 | struct JsonReader { 9 | std::string fecthJson() { return "{}\n"; } 10 | }; 11 | 12 | struct Presentaion { 13 | void Show(XmlReader *reader) { 14 | std::cout << reader->read(); /*do something with reader*/ 15 | } 16 | }; 17 | 18 | // composition adapter 19 | struct JsonToXmlAdapter : public XmlReader { 20 | JsonToXmlAdapter(JsonReader *json_reader) : json_reader_(json_reader) {} 21 | 22 | std::string read() override { 23 | std::cout << json_reader_->fecthJson(); 24 | return "<>\n"; 25 | } 26 | 27 | private: 28 | JsonReader *json_reader_; 29 | }; 30 | 31 | // class adapter 32 | struct JsonToXmlAdapterClass : public XmlReader, public JsonReader { 33 | std::string read() override { 34 | std::cout << JsonReader::fecthJson(); 35 | return "<>\n"; 36 | } 37 | }; 38 | 39 | int main() { 40 | Presentaion p; 41 | XmlReader *xml_reader = new XmlReader; 42 | p.Show(xml_reader); 43 | 44 | 45 | JsonReader *json_reader = new JsonReader; 46 | // p.Show(json_reader); // недопустимо 47 | 48 | { 49 | // composition adaptor 50 | std::cout << "composition: \n"; 51 | JsonToXmlAdapter* json_to_xml_adater = new JsonToXmlAdapter(json_reader); 52 | p.Show(json_to_xml_adater); 53 | } 54 | 55 | { 56 | // class adaptor 57 | std::cout << "class: \n"; 58 | JsonToXmlAdapterClass* json_to_xml_adater = new JsonToXmlAdapterClass; 59 | p.Show(json_to_xml_adater); 60 | } 61 | 62 | std::stack s; 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /examples/lecture2/028_matrix_sums_by_columns.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define RETRIES 100 6 | #define N 1000 7 | 8 | void sum1(double A[N][N], double S[N]) { 9 | for (size_t j = 0; j < N; ++j) { 10 | for (size_t i = 0; i < N; ++i) { 11 | S[j] += A[i][j]; 12 | } 13 | } 14 | } 15 | 16 | void sum2(double A[N][N], double S[N]) { 17 | for (size_t i = 0; i < N; ++i) { 18 | for (size_t j = 0; j < N; ++j) { 19 | S[j] += A[i][j]; 20 | } 21 | } 22 | } 23 | 24 | void fill_random(double A[N][N]) { 25 | for (size_t i = 0; i < N; ++i) { 26 | for (size_t j = 0; j < N; ++j) { 27 | A[i][j] = rand(); 28 | } 29 | } 30 | } 31 | 32 | int main(int argc, char *argv[]) { 33 | srand(time(NULL)); 34 | double A[N][N]; 35 | 36 | double time = 0; 37 | for (size_t i = 0; i < RETRIES; ++i) { 38 | fill_random(A); 39 | double S[N] = {0}; 40 | clock_t begin = clock(); 41 | sum1(A, S); 42 | clock_t end = clock(); 43 | time += (double)(end - begin) / CLOCKS_PER_SEC; 44 | } 45 | double avg_time = time / RETRIES; 46 | printf("First method - average time: %f\n", avg_time); 47 | 48 | time = 0; 49 | for (size_t i = 0; i < RETRIES; ++i) { 50 | fill_random(A); 51 | double S[N] = {0}; 52 | clock_t begin = clock(); 53 | sum2(A, S); 54 | clock_t end = clock(); 55 | time += (double)(end - begin) / CLOCKS_PER_SEC; 56 | } 57 | avg_time = time / RETRIES; 58 | printf("Second method - average time: %f\n", avg_time); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /examples/lecture1/009_arrays_as_function_arguments.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define YSIZE 2 4 | #define ZSIZE 3 5 | 6 | void foo(size_t, size_t, int [*][*]); 7 | void bar(int (*)[YSIZE][ZSIZE], size_t); 8 | 9 | void foo(size_t x, size_t y, int a[x][y]) { 10 | printf("foo()\n"); 11 | for (size_t i = 0; i < x; ++i) { 12 | for (size_t j = 0; j < y; ++j) { 13 | printf("%d ", a[i][j]); 14 | } 15 | printf("\n"); 16 | } 17 | } 18 | 19 | void bar(int a[][YSIZE][ZSIZE], size_t x) { 20 | printf("bar()\n"); 21 | for (size_t i = 0; i < x; ++i) { 22 | for (size_t j = 0; j < YSIZE; ++j) { 23 | for (size_t k = 0; k < ZSIZE; ++k) { 24 | printf("%d ", a[i][j][k]); 25 | } 26 | printf("\n"); 27 | } 28 | printf("\n"); 29 | } 30 | } 31 | 32 | int main(int argc, char *argv[]) { 33 | int N = 2; 34 | int M = N * N; 35 | int a[N][M] /* = { 0 } */; // VLA arrays can not be initialized 36 | printf("a\n"); 37 | for (size_t i = 0; i < N; ++i) { 38 | for (size_t j = 0; j < M; ++j) { 39 | a[i][j] = i + j; 40 | printf("%d ", a[i][j]); 41 | } 42 | printf("\n"); 43 | } 44 | foo(N, M, a); 45 | int L = M * N; 46 | int b[L][YSIZE][ZSIZE]; 47 | printf("b\n"); 48 | for (size_t i = 0; i < L; ++i) { 49 | for (size_t j = 0; j < YSIZE; ++j) { 50 | for (size_t k = 0; k < ZSIZE; ++k) { 51 | b[i][j][k] = i + j + k; 52 | printf("%d ", b[i][j][k]); 53 | } 54 | printf("\n"); 55 | } 56 | printf("\n"); 57 | } 58 | bar(b, L); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /examples/lecture1/007_two_dimensional_array_vs_vector_of_vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | int *a; 7 | int **b; 8 | int N = 10; 9 | int M = 10; 10 | /* 2 dimensional array */ 11 | printf("2-dim\n"); 12 | a = (int *)malloc(N * M * sizeof(int)); 13 | if (a) { 14 | for (size_t i = 0; i < N; ++i) { 15 | for (size_t j = 0; j < M; ++j) { 16 | a[i * M + j] = i + j; 17 | printf("%2d ", a[i * M + j]); 18 | } 19 | printf("\n"); 20 | } 21 | 22 | printf("2-dim-linear:\n"); 23 | for (size_t i = 0; i < N * M; ++i) { 24 | printf("%2d ", a[i]); 25 | } 26 | printf("\n"); 27 | free(a); 28 | } 29 | 30 | /* vector of vectors */ 31 | b = (int **)malloc(N * sizeof(int *)); 32 | if (b) { 33 | bool ok = true; 34 | for (size_t i = 0; i < N; ++i) { 35 | b[i] = (int *)malloc(M * sizeof(int)); 36 | if (!b[i]) { 37 | for (size_t j = 0; j < i; ++j) { 38 | free(b[j]); 39 | } 40 | ok = false; 41 | break; 42 | } 43 | for (size_t j = 0; j < M; ++j) { 44 | b[i][j] = i + j; 45 | } 46 | } 47 | if (ok) { 48 | for (size_t i = 0; i < N; ++i) { 49 | printf("%p - %p\n", (void *)b[i], (void *)&b[i][M - 1]); 50 | } 51 | for (size_t i = 0; i < N; ++i) { 52 | free(b[i]); 53 | } 54 | } 55 | free(b); 56 | } 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /examples/lecture2/001_getopt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | int opt, n; 8 | /* 9 | '-' - обработка non-option-аргументов вместо их перемещения в конец argv. Если выставляется, то первым 10 | ':' - отключение печати ошибок и обработка ошибки отсутствия аргумента :. Если выставляется, то перед параметрами 11 | 'n::' - опциональный параметр n. Валидно -n или -nvalue без пробела. -n value - это -n и non-option value 12 | 'c:' - параметр c с обязательным аргументом 13 | 'h' - параметр-флаг 14 | */ 15 | char *opts = "-:n::c:h", c; 16 | 17 | printf("Got %d args\n", argc); 18 | 19 | // opterr = 0; // отключает печать ошибок от getopt при отсутствии : в начале 20 | 21 | while ((opt = getopt(argc, argv, opts)) != -1) { 22 | printf("optopt=%c, opt=%c, optarg=%s\n", optopt, opt, optarg); 23 | switch (opt) { 24 | case 'n': n = optarg ? atoi(optarg) : 0; break; 25 | case 'c': c = optarg[0]; break; 26 | case 'h': printf("Usage: %s [-h|-n10|-c 'a'] \n", argv[0]); break; 27 | case '?': printf("Unknown option: %c\n", optopt); break; 28 | case ':': printf("Missing arg for %c\n", optopt); break; // ':' in opts 29 | case 1 : printf("Non-option arg: %s\n", optarg); break; // '-' in opts 30 | default: break; 31 | } 32 | } 33 | printf("n=%d, c=%c\n", n, c); 34 | 35 | // если в opts есть -, то здесь есть параметры только после -- 36 | // если нет - то ещё и те non-option, которые были сдвинуты в конец argv до -- 37 | 38 | printf("\nRemained args after -- if exist\n"); 39 | while (optind < argc) { 40 | printf("%s\n", argv[optind]); 41 | optind++; 42 | } 43 | } -------------------------------------------------------------------------------- /examples/lecture1/006_two_dimensional_arrays.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ROWS 2 4 | #define COLS 3 5 | 6 | int main(int argc, char *argv[]) { 7 | int a[ROWS][COLS] = { 8 | {0, 1}, 9 | {2, 3, 4} 10 | }; 11 | int b[ROWS][COLS] = {0, 1, 2, 3, 4}; 12 | 13 | printf("a\n"); 14 | for (size_t i = 0; i < ROWS; ++i) { 15 | for (size_t j = 0; j < COLS; ++j) { 16 | printf("%d ", a[i][j]); 17 | } 18 | printf("\n"); 19 | } 20 | printf("\n"); 21 | 22 | printf("a as linear\n"); 23 | int (*linear)[ROWS * COLS] = &a; 24 | for (size_t i = 0; i < ROWS * COLS; ++i) { 25 | printf("%d ", (*linear)[i]); 26 | } 27 | printf("\n"); 28 | printf("\n"); 29 | 30 | printf("b\n"); 31 | for (size_t i = 0; i < ROWS; ++i) { 32 | for (size_t j = 0; j < COLS; ++j) { 33 | printf("%d ", b[i][j]); 34 | } 35 | printf("\n"); 36 | } 37 | printf("\n"); 38 | 39 | printf("b as linear\n"); 40 | linear = &b; 41 | for (size_t i = 0; i < ROWS * COLS; ++i) { 42 | printf("%d ", (*linear)[i]); 43 | } 44 | printf("\n"); 45 | 46 | int k[3][5]; 47 | int (*pk)[5]; 48 | int *p[5]; 49 | 50 | pk = k; 51 | pk[0][0] = 1; 52 | *pk[0] = 2; 53 | printf("pk[0][0] = %d\n", pk[0][0]); 54 | **pk = 3; 55 | printf("pk[0][0] = %d\n", pk[0][0]); 56 | 57 | double *pd, **ppd; 58 | double (*pda)[2]; 59 | double dbl32[3][2]; 60 | double dbl23[2][3]; 61 | 62 | // correct use 63 | pd = &dbl32[0][0]; 64 | pd = dbl32[1]; 65 | pda = dbl32; 66 | ppd = &pd; 67 | 68 | // incorrect use 69 | pd = dbl32; 70 | pda = dbl23; 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/031_bridge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | // logger.h 8 | // -------------------------------- 9 | struct LoggerImpl; 10 | struct Logger { 11 | Logger(LoggerImpl *p) : pimpl(p) {}; 12 | virtual ~Logger() = default; 13 | virtual void log(string &str) = 0; 14 | 15 | protected: 16 | LoggerImpl *pimpl = nullptr; 17 | }; 18 | // -------------------------------- 19 | 20 | // logger_impl.h 21 | // -------------------------------- 22 | struct LoggerImpl { 23 | virtual ~LoggerImpl() {} 24 | virtual void console_log(string &str) = 0; 25 | 26 | virtual void file_log(const std::string& str) = 0; 27 | 28 | virtual void socket_log(const std::string& str) = 0; 29 | }; 30 | 31 | struct ST_LoggerImpl : public LoggerImpl { 32 | void console_log(string &str) { std::cout << "ST == " << str; }; 33 | 34 | virtual void file_log(const std::string& str) {}; 35 | }; 36 | 37 | struct MT_LoggerImpl : public LoggerImpl { 38 | void console_log(string &str) { std::cout << "MT == " << str; };; 39 | }; 40 | // -------------------------------- 41 | 42 | 43 | // console_logger.h 44 | // -------------------------------- 45 | 46 | #define MT 47 | 48 | struct ConsoleLogger : public Logger { 49 | ConsoleLogger() 50 | : Logger( 51 | #ifdef MT 52 | new MT_LoggerImpl() 53 | #else 54 | new ST_LoggerImpl() 55 | #endif 56 | ){}; 57 | void log(string &str){ pimpl->console_log(str); }; 58 | }; 59 | 60 | struct FileLogger { 61 | void log(string &str){ pimpl->file_log(str); }; 62 | }; 63 | // -------------------------------- 64 | 65 | int main() { 66 | Logger * p = new ConsoleLogger(); 67 | std::string mess = "some message"; 68 | p->log(mess); 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /2017_2/examples/patterns/031_bridge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | // logger.h 8 | // -------------------------------- 9 | struct LoggerImpl; 10 | struct Logger { 11 | Logger(LoggerImpl *p) : pimpl(p) {}; 12 | virtual ~Logger() = default; 13 | virtual void log(string &str) = 0; 14 | 15 | protected: 16 | LoggerImpl *pimpl = nullptr; 17 | }; 18 | // -------------------------------- 19 | 20 | // logger_impl.h 21 | // -------------------------------- 22 | struct LoggerImpl { 23 | virtual ~LoggerImpl() {} 24 | virtual void console_log(string &str) = 0; 25 | 26 | virtual void file_log(const std::string& str) = 0; 27 | 28 | virtual void socket_log(const std::string& str) = 0; 29 | }; 30 | 31 | struct ST_LoggerImpl : public LoggerImpl { 32 | void console_log(string &str) { std::cout << "ST == " << str; }; 33 | 34 | virtual void file_log(const std::string& str) {}; 35 | }; 36 | 37 | struct MT_LoggerImpl : public LoggerImpl { 38 | void console_log(string &str) { std::cout << "MT == " << str; };; 39 | }; 40 | // -------------------------------- 41 | 42 | 43 | // console_logger.h 44 | // -------------------------------- 45 | 46 | #define MT 47 | 48 | struct ConsoleLogger : public Logger { 49 | ConsoleLogger() 50 | : Logger( 51 | #ifdef MT 52 | new MT_LoggerImpl() 53 | #else 54 | new ST_LoggerImpl() 55 | #endif 56 | ){}; 57 | void log(string &str){ pimpl->console_log(str); }; 58 | }; 59 | 60 | struct FileLogger { 61 | void log(string &str){ pimpl->file_log(str); }; 62 | }; 63 | // -------------------------------- 64 | 65 | int main() { 66 | Logger * p = new ConsoleLogger(); 67 | std::string mess = "some message"; 68 | p->log(mess); 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /examples/lecture3/014_move_constructor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Alpha { 4 | private: 5 | std::size_t sz; 6 | double *d; 7 | public: 8 | Alpha(); 9 | Alpha(const Alpha &a); 10 | Alpha(Alpha &&a); 11 | ~Alpha(); 12 | }; 13 | 14 | Alpha::Alpha() : sz(0), d(NULL) { 15 | std::cout << "Alpha()" << std::endl; 16 | } 17 | 18 | Alpha::~Alpha() { 19 | std::cout << "~Alpha()" << std::endl; 20 | delete []d; 21 | } 22 | 23 | Alpha::Alpha(const Alpha &a) : sz(a.sz) { 24 | std::cout << "Alpha(const Alpha &a)" << std::endl; 25 | d = new double[sz]; 26 | for (std::size_t i = 0; i < sz; ++i) { 27 | d[i] = a.d[i]; 28 | } 29 | } 30 | 31 | Alpha::Alpha(Alpha &&a) : sz(a.sz) { 32 | std::cout << "Alpha(Alpha &&a)" << std::endl; 33 | d = a.d; 34 | a.d = nullptr; 35 | a.sz = 0; 36 | } 37 | 38 | Alpha foo(Alpha arg) { 39 | return arg; 40 | } 41 | 42 | void bar(Alpha arg) { 43 | } 44 | 45 | int main(int argc, char *argv[]) { 46 | std::cout << "Alpha alp1 = foo(Alpha())" << std::endl; 47 | Alpha alp1 = foo(Alpha()); 48 | std::cout << "foo(alp1)" << std::endl; 49 | foo(alp1); 50 | std::cout << "foo(std::move(alp1))" << std::endl; 51 | foo(std::move(alp1)); 52 | std::cout << "Alpha alp2 = alp1" << std::endl; 53 | Alpha alp2 = alp1; 54 | std::cout << "Alpha alp3(alp1)" << std::endl; 55 | Alpha alp3(alp1); 56 | std::cout << "Alpha alp4 = std::move(alp1)" << std::endl; 57 | Alpha alp4 = std::move(alp1); 58 | std::cout << "Alpha alp5(std::move(alp1))" << std::endl; 59 | Alpha alp5(std::move(alp1)); 60 | std::cout << "bar(alp2)" << std::endl; 61 | bar(alp2); 62 | std::cout << "bar(std::move(alp2))" << std::endl; 63 | bar(std::move(alp2)); 64 | std::cout << "end of scope" << std::endl; 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /2017_2/examples/stl/038_bad_lru_cache.cpp: -------------------------------------------------------------------------------- 1 | #ifndef LIBUTIL_LRU_CACHE_HPP__ 2 | #define LIBUTIL_LRU_CACHE_HPP__ 3 | 4 | #include 5 | 6 | namespace libutil { 7 | 8 | template class LastUsedCache { 9 | struct record_t { 10 | TItem data; 11 | uint64_t gen; 12 | }; 13 | 14 | typedef std::unordered_map cache_t; 15 | cache_t cache_; 16 | size_t max_size_; 17 | uint64_t generation_; 18 | 19 | public: 20 | LastUsedCache(size_t nelems) : max_size_(nelems), generation_(0) {} 21 | 22 | bool find(Tkey key, TItem *item = nullptr) const { 23 | typename cache_t::const_iterator it = cache_.find(key); 24 | 25 | if (it == cache_.end()) 26 | return false; 27 | else { 28 | if (item) 29 | *item = it->second.data; 30 | return true; 31 | } 32 | } 33 | 34 | void insert(Tkey key, const TItem &data) { 35 | if (max_size_ != 0U) { 36 | record_t rec{data, ++generation_}; 37 | 38 | std::pair result = 39 | cache_.insert(typename cache_t::value_type(key, rec)); 40 | 41 | if (result.second) { 42 | if (cache_.size() > max_size_) { 43 | uint64_t min_gen = -1; 44 | for (typename cache_t::value_type &val : cache_) 45 | min_gen = std::min(min_gen, val.second.gen); 46 | 47 | for (typename cache_t::iterator val_it = cache_.begin(); 48 | val_it != cache_.end(); ++val_it) 49 | if (val_it->second.gen == min_gen) { 50 | cache_.erase(val_it); 51 | break; 52 | } 53 | } 54 | } else { 55 | result.first->second.gen = ++generation_; 56 | } 57 | } 58 | } 59 | 60 | size_t size() const { return cache_.size(); } 61 | 62 | bool empty() const { return (size() == 0); } 63 | 64 | void clear() { cache_.clear(); } 65 | }; 66 | 67 | } // namespace libutil 68 | -------------------------------------------------------------------------------- /2017_2/examples/stl/039_good_lru_cache.cpp: -------------------------------------------------------------------------------- 1 | #ifndef LIBUTIL_LRU_CACHE_HPP__ 2 | #define LIBUTIL_LRU_CACHE_HPP__ 3 | 4 | #include 5 | #include 6 | 7 | namespace libutil { 8 | 9 | template class lru_cache { 10 | typedef std::list lru_t; 11 | lru_t lru_; 12 | 13 | struct lru_record_t { 14 | TItem data; 15 | typename lru_t::iterator lru_it; 16 | lru_record_t(const TItem &dat, const typename lru_t::iterator &it) 17 | : data(dat), lru_it(it) {} 18 | }; 19 | 20 | typedef boost::unordered_map cache_t; 21 | cache_t cache_; 22 | size_t max_size_; 23 | 24 | public: 25 | lru_cache(size_t nelems) : max_size_(nelems) {} 26 | 27 | bool find(Tkey key, TItem *item = NULL) const { 28 | typename cache_t::const_iterator it = cache_.find(key); 29 | 30 | if (it == cache_.end()) 31 | return false; 32 | else { 33 | if (item) 34 | *item = it->second.data; 35 | 36 | return true; 37 | } 38 | } 39 | 40 | void insert(Tkey key, const TItem &data) { 41 | if (max_size_ != 0U) { 42 | lru_.push_front(key); 43 | lru_record_t rec(data, lru_.begin()); 44 | 45 | std::pair result = 46 | cache_.insert(typename cache_t::value_type(key, rec)); 47 | 48 | if (result.second) { 49 | if (cache_.size() > max_size_) { 50 | Tkey older_key = lru_.back(); 51 | lru_.pop_back(); 52 | cache_.erase(older_key); 53 | } 54 | } else { 55 | typename cache_t::iterator &oldit = result.first; 56 | lru_.erase(oldit->second.lru_it); 57 | oldit->second = rec; 58 | } 59 | } 60 | } 61 | 62 | size_t size() const { return cache_.size(); } 63 | 64 | bool empty() const { return (size() == 0); } 65 | 66 | void clear() { 67 | cache_.clear(); 68 | lru_.clear(); 69 | } 70 | }; 71 | 72 | } // namespace libutil 73 | 74 | 75 | #endif // !LIBUTIL_LRU_CACHE_HPP__ 76 | -------------------------------------------------------------------------------- /examples/lecture3/008_default_copy_constructor_and_assign_operator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class A { 5 | private: 6 | char *s; 7 | public: 8 | A(const char *s) : s(new char[strlen(s)]) { 9 | std::cout << "A()" << std::endl; 10 | strcpy(this->s, s); 11 | } 12 | /*A(const A &a) : s(new char[strlen(a.s)]) { 13 | std::cout << "A(const A &a)" << std::endl; 14 | strcpy(this->s, a.s); 15 | }*/ 16 | A(const A &a) : A(a.s) { // c++11 17 | std::cout << "A(const &a)" << std::endl; 18 | } 19 | A &operator=(A const &a) { 20 | std::cout << "A &operator=(A &a)" << std::endl; 21 | A tmp(a); 22 | std::swap(this->s, tmp.s); 23 | return *this; 24 | } 25 | ~A() { 26 | std::cout << "~A()" << std::endl; 27 | delete []s; 28 | } 29 | void print() { 30 | std::cout << s << std::endl; 31 | } 32 | }; 33 | 34 | class B { 35 | private: 36 | char *s; 37 | public: 38 | B(const char *s) : s(new char[strlen(s)]) { 39 | std::cout << "B()" << std::endl; 40 | strcpy(this->s, s); 41 | } 42 | ~B() { 43 | std::cout << "~B()" << std::endl; 44 | delete []s; 45 | } 46 | void print() { 47 | std::cout << s << std::endl; 48 | } 49 | private: 50 | /*B(const B &b) { 51 | std::cout << "B(const B &b)" << std::endl; 52 | }*/ 53 | B(const B &b); 54 | B &operator=(B &b); 55 | friend class C; 56 | }; 57 | 58 | class C { 59 | private: 60 | B b; 61 | public: 62 | C(B &b) : b(b) {} 63 | }; 64 | 65 | int main(int argc, char *argv[]) { 66 | char s[] = "Hello"; 67 | A a1(s); 68 | a1.print(); 69 | A a2(a1); 70 | a2.print(); 71 | a2 = a1; 72 | a2.print(); 73 | B b1(s); 74 | b1.print(); 75 | /*B b2(b1); 76 | b2.print(); 77 | b2 = b1; 78 | b2.print();*/ 79 | /*B *b2 = &b1; 80 | b2->print(); 81 | *b2 = b1; 82 | b2->print();*/ 83 | C c(b1); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /examples/lecture1/005_dynamic_memory_management.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define SIZE 10 6 | 7 | int main(int argc, char *argv[]) { 8 | int *a = (int *)malloc(SIZE * sizeof(int)); 9 | /*if (a) { 10 | for (size_t i = 0; i < SIZE; ++i) { 11 | printf("%d ", a[i]); 12 | } 13 | }*/ 14 | 15 | printf("\n"); 16 | int *b = (int *)calloc(SIZE, sizeof(int)); 17 | if (b) { 18 | for (size_t i = 0; i < SIZE; ++i) { 19 | printf("%d ", b[i]); 20 | } 21 | } 22 | 23 | printf("\n"); 24 | char *str_a = (char *)malloc((SIZE + 1) * sizeof(char)); // One more for '\0' 25 | /*if (str_a) { 26 | printf("uninitialized malloc string (%s) length: %ld\n", str_a, strlen(str_a)); 27 | str_a[0] = '\0'; // String must terminate with '\0' 28 | printf("initialized string length: %ld\n", strlen(str_a)); 29 | }*/ 30 | 31 | char *str_b = (char *)calloc((SIZE + 1), sizeof(char)); // One more for '\0' 32 | if (str_b) { 33 | printf("uninitialized calloc string (%s) length: %ld\n", str_b, strlen(str_b)); 34 | str_b[0] = '\0'; // String must terminate with '\0' 35 | printf("initialized string length: %ld\n", strlen(str_b)); 36 | } 37 | 38 | free(a); 39 | printf("a after free: %p\n", a); 40 | a = NULL; 41 | 42 | int *new_b = realloc(b, 0); 43 | printf("b realloc: %p -> %p\n", b, new_b); 44 | // free(b); 45 | b = NULL; 46 | 47 | int *new_a = realloc(a, 2 * SIZE * sizeof(int)); 48 | printf("a realloc: %p -> %p\n", a, new_a); 49 | /*if (new_a) { 50 | for (size_t i = 0; i < 2 * SIZE; ++i) { 51 | printf("%d ", new_a[i]); 52 | } 53 | }*/ 54 | printf("\n"); 55 | 56 | if (new_a) { 57 | free(new_a); 58 | } 59 | if (new_b) { 60 | free(new_b); 61 | } 62 | if (str_a) { 63 | free(str_a); 64 | } 65 | if (str_b) { 66 | free(str_b); 67 | } 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/026_diamond_inheritance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace diamond_problem { 4 | class A { 5 | public: 6 | A() { std::cout << "ctor A()" << std::endl; } 7 | explicit A(int a) { std::cout << "ctor A() << a = " << a << std::endl; } 8 | 9 | virtual void foo() { std::cout << std::endl << std::endl; } 10 | 11 | int a = 0; 12 | int b = 0; 13 | }; 14 | 15 | class B : public virtual A { 16 | public: 17 | B() { std::cout << "ctor B()" << std::endl; } 18 | explicit B(int a) : A(a) { std::cout << "ctor B() << a " << a << std::endl; } 19 | }; 20 | 21 | class C : public virtual A { 22 | public: 23 | C() { std::cout << "ctor C()" << std::endl; } 24 | }; 25 | 26 | class NonVirtual { 27 | public: 28 | NonVirtual() { std::cout << "ctor Nonvirtual()" << std::endl; } 29 | }; 30 | 31 | class D : public NonVirtual, public B, public C { 32 | public: 33 | D() : A(5), B(5) { std::cout << "ctor D()" << std::endl; } 34 | }; 35 | } // namespace diamond_problem 36 | 37 | namespace another_inh_problem { 38 | class B { 39 | public: 40 | B() { std::cout << "ctor B()" << std::endl; } 41 | 42 | virtual void foo() { std::cout << std::endl << std::endl; } 43 | }; 44 | 45 | class C { 46 | public: 47 | C() { std::cout << "ctor C()" << std::endl; } 48 | 49 | virtual void foo() { std::cout << std::endl << std::endl; } 50 | }; 51 | 52 | class D : public B, public C { 53 | public: 54 | using B::foo; 55 | D() { std::cout << "ctor D()" << std::endl; } 56 | }; 57 | } // namespace another_inh_problem 58 | 59 | int main() { 60 | { 61 | using namespace diamond_problem; 62 | D d1; 63 | // d1.foo(); 64 | 65 | // std::cout << sizeof(diamond_problem::A) << std::endl; 66 | // std::cout << sizeof(diamond_problem::B) << std::endl; 67 | // std::cout << sizeof(diamond_problem::C) << std::endl; 68 | // std::cout << sizeof(diamond_problem::D) << std::endl; 69 | // std::cout << std::endl; 70 | } 71 | std::cout << std::endl; 72 | { 73 | another_inh_problem::D d; 74 | d.foo(); 75 | } 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /examples/lecture2/029_matrix_mul.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define RETRIES 100 6 | #define N 200 7 | 8 | void mul1(double A[N][N], double B[N][N], double C[N][N]) { 9 | for (size_t i = 0; i < N; ++i) { 10 | for (size_t j = 0; j < N; ++j) { 11 | for (size_t k = 0; k < N; ++k) { 12 | C[i][j] += A[i][k] * B[k][j]; 13 | } 14 | } 15 | } 16 | } 17 | 18 | void mul2(double A[N][N], double B[N][N], double C[N][N]) { 19 | double transpB[N][N]; 20 | for (size_t i = 0; i < N; ++i) { 21 | for (size_t j = 0; j < N; ++j) { 22 | transpB[i][j] = B[j][i]; 23 | } 24 | } 25 | for (size_t i = 0; i < N; ++i) { 26 | for (size_t j = 0; j < N; ++j) { 27 | for (size_t k = 0; k < N; ++k) { 28 | C[i][j] += A[i][k] * transpB[j][k]; 29 | } 30 | } 31 | } 32 | } 33 | 34 | void fill_random(double A[N][N]) { 35 | for (size_t i = 0; i < N; ++i) { 36 | for (size_t j = 0; j < N; ++j) { 37 | A[i][j] = rand(); 38 | } 39 | } 40 | } 41 | 42 | int main(int argc, char *argv[]) { 43 | srand(time(NULL)); 44 | double A[N][N]; 45 | double B[N][N]; 46 | 47 | double time = 0; 48 | for (size_t i = 0; i < RETRIES; ++i) { 49 | fill_random(A); 50 | fill_random(B); 51 | double C[N][N]; 52 | clock_t begin = clock(); 53 | mul1(A, B, C); 54 | clock_t end = clock(); 55 | time += (double)(end - begin) / CLOCKS_PER_SEC; 56 | } 57 | double avg_time = time / RETRIES; 58 | printf("First method - average time: %f\n", avg_time); 59 | 60 | time = 0; 61 | for (size_t i = 0; i < RETRIES; ++i) { 62 | fill_random(A); 63 | fill_random(B); 64 | double C[N][N]; 65 | clock_t begin = clock(); 66 | mul2(A, B, C); 67 | clock_t end = clock(); 68 | time += (double)(end - begin) / CLOCKS_PER_SEC; 69 | } 70 | avg_time = time / RETRIES; 71 | printf("Second method - average time: %f\n", avg_time); 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /examples/lecture3/010_initializer_list_vs_constructor_body.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class A { 4 | private: 5 | const int a; 6 | const int &b; 7 | public: 8 | A() : a(0), b(a) { 9 | std::cout << "A()" << std::endl; 10 | } 11 | A(const A &a) : a(0), b(this->a) { 12 | std::cout << "A(const A &a)" << std::endl; 13 | } 14 | A &operator=(A &a) { 15 | std::cout << "A &operator=(A &a)" << std::endl; 16 | return a; 17 | } 18 | }; 19 | 20 | class B { 21 | public: 22 | B() { 23 | std::cout << "B()" << std::endl; 24 | } 25 | B(const B &b) { 26 | std::cout << "B(const B &b)" << std::endl; 27 | } 28 | B &operator=(B &b) { 29 | std::cout << "B &operator=(B &b)" << std::endl; 30 | return b; 31 | } 32 | }; 33 | 34 | class C { 35 | private: 36 | A a; 37 | B b; 38 | public: 39 | C() { 40 | std::cout << "C()" << std::endl; 41 | } 42 | C(A &a, B &b) { 43 | this->a = a; 44 | this->b = b; 45 | } 46 | C(const C &c) { 47 | std::cout << "C(const C &c)" << std::endl; 48 | } 49 | C &operator=(C &c) { 50 | std::cout << "C &operator=(C &c)" << std::endl; 51 | return c; 52 | } 53 | }; 54 | 55 | class D { 56 | private: 57 | A a; 58 | B b; 59 | C c; 60 | public: 61 | D() { 62 | std::cout << "D()" << std::endl; 63 | } 64 | D(A &a, B &b, C &c) { 65 | this->a = a; 66 | this->b = b; 67 | this->c = c; 68 | } 69 | D(const D &d) { 70 | std::cout << "D(const D &d)" << std::endl; 71 | } 72 | D &operator=(D &d) { 73 | std::cout << "D &operator=(D &d)" << std::endl; 74 | return d; 75 | } 76 | }; 77 | 78 | class E { 79 | private: 80 | A a; 81 | B b; 82 | C c; 83 | D d; 84 | public: 85 | E(A &a, B &b, C &c, D &d) : a(a), b(b), c(c), d(d) {} 86 | }; 87 | 88 | int main(int argc, char *argv[]) { 89 | A a; 90 | B b; 91 | std::cout << "C(a, b)" << std::endl; 92 | C c(a, b); 93 | std::cout << "D(a, b, c)" << std::endl; 94 | D d(a, b, c); 95 | std::cout << "E(a, b, c, d)" << std::endl; 96 | E e(a, b, c, d); 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/029_abstract_factory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Этот паттерн предполагает, что у вас есть несколько семейств 5 | // продуктов, находящихся в отдельных иерархиях классов 6 | // (Button/Checkbox). Продукты одного семейства должны иметь 7 | // общий интерфейс. 8 | struct Button { 9 | virtual void paint() = 0; 10 | }; 11 | 12 | // Семейства продуктов имеют те же вариации (macOS/Windows). 13 | struct WinButton : public Button { 14 | void paint() override { std::cout << "WinButton\n"; }; 15 | }; 16 | 17 | // Семейства продуктов имеют те же вариации (macOS/Windows). 18 | struct MacButton : public Button { 19 | void paint() override { std::cout << "MacButton\n"; }; 20 | }; 21 | 22 | struct CheckBox { 23 | virtual void paint() = 0; 24 | }; 25 | 26 | // Семейства продуктов имеют те же вариации (macOS/Windows). 27 | struct WinCheckBox : public CheckBox { 28 | void paint() override { std::cout << "WinCheckBox\n"; }; 29 | }; 30 | 31 | // Семейства продуктов имеют те же вариации (macOS/Windows). 32 | struct MacCheckBox : public CheckBox { 33 | void paint() override { std::cout << "MacCheckBox\n"; }; 34 | }; 35 | 36 | 37 | struct GUIFactory { 38 | virtual Button *createButton() = 0; 39 | virtual CheckBox *createCheckBox() = 0; 40 | }; 41 | 42 | // Каждая конкретная фабрика знает и создаёт только продукты 43 | // своей вариации. 44 | struct WinGUIFactory : public GUIFactory { 45 | Button *createButton() { return new WinButton(); }; 46 | 47 | CheckBox *createCheckBox() { return new WinCheckBox(); }; 48 | }; 49 | 50 | // Несмотря на то, что фабрики оперируют конкретными классами, 51 | // их методы возвращают абстрактные типы продуктов. Благодаря 52 | // этому фабрики можно взаимозаменять, не изменяя клиентский 53 | // код. 54 | struct MacGUIFactory : public GUIFactory { 55 | Button *createButton() { return new MacButton(); }; 56 | CheckBox *createCheckBox() { return new MacCheckBox(); }; 57 | }; 58 | 59 | int main() { 60 | 61 | 62 | GUIFactory* factory = new MacGUIFactory(); 63 | 64 | Button* button = factory->createButton(); 65 | button->paint(); 66 | CheckBox* checkbox = factory->createCheckBox(); 67 | checkbox->paint(); 68 | 69 | std::stack s; 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /2017_2/examples/patterns/029_abstract_factory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Этот паттерн предполагает, что у вас есть несколько семейств 5 | // продуктов, находящихся в отдельных иерархиях классов 6 | // (Button/Checkbox). Продукты одного семейства должны иметь 7 | // общий интерфейс. 8 | struct Button { 9 | virtual void paint() = 0; 10 | }; 11 | 12 | // Семейства продуктов имеют те же вариации (macOS/Windows). 13 | struct WinButton : public Button { 14 | void paint() override { std::cout << "WinButton\n"; }; 15 | }; 16 | 17 | // Семейства продуктов имеют те же вариации (macOS/Windows). 18 | struct MacButton : public Button { 19 | void paint() override { std::cout << "MacButton\n"; }; 20 | }; 21 | 22 | struct CheckBox { 23 | virtual void paint() = 0; 24 | }; 25 | 26 | // Семейства продуктов имеют те же вариации (macOS/Windows). 27 | struct WinCheckBox : public CheckBox { 28 | void paint() override { std::cout << "WinCheckBox\n"; }; 29 | }; 30 | 31 | // Семейства продуктов имеют те же вариации (macOS/Windows). 32 | struct MacCheckBox : public CheckBox { 33 | void paint() override { std::cout << "MacCheckBox\n"; }; 34 | }; 35 | 36 | 37 | struct GUIFactory { 38 | virtual Button *createButton() = 0; 39 | virtual CheckBox *createCheckBox() = 0; 40 | }; 41 | 42 | // Каждая конкретная фабрика знает и создаёт только продукты 43 | // своей вариации. 44 | struct WinGUIFactory : public GUIFactory { 45 | Button *createButton() { return new WinButton(); }; 46 | 47 | CheckBox *createCheckBox() { return new WinCheckBox(); }; 48 | }; 49 | 50 | // Несмотря на то, что фабрики оперируют конкретными классами, 51 | // их методы возвращают абстрактные типы продуктов. Благодаря 52 | // этому фабрики можно взаимозаменять, не изменяя клиентский 53 | // код. 54 | struct MacGUIFactory : public GUIFactory { 55 | Button *createButton() { return new MacButton(); }; 56 | CheckBox *createCheckBox() { return new MacCheckBox(); }; 57 | }; 58 | 59 | int main() { 60 | 61 | 62 | GUIFactory* factory = new MacGUIFactory(); 63 | 64 | Button* button = factory->createButton(); 65 | button->paint(); 66 | CheckBox* checkbox = factory->createCheckBox(); 67 | checkbox->paint(); 68 | 69 | std::stack s; 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /examples/lecture2/002_getopt_long.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) { 7 | int c, config_id, opt_idx, should_create = 0; 8 | 9 | /* 10 | struct option { 11 | const char *name; // имя без "-" 12 | int has_arg; // 0 - без аргумента, 1 - обязательный, 2 - необязательный 13 | int *flag; // NULL -> getopt возвращает val 14 | // иначе -> getopt возвращает 0, *flag = val 15 | int val; 16 | } 17 | */ 18 | 19 | struct option options[] = { 20 | { "help", no_argument, NULL, 'h' }, 21 | { "config_id", required_argument, NULL, 'c' }, 22 | { "create", optional_argument, &should_create, 1 }, 23 | { NULL, 0, NULL, 0 } 24 | }; 25 | 26 | while ( (c = getopt_long(argc, argv, "-:c:h", options, &opt_idx)) != -1 ) { 27 | printf("c=%c, optopt=%c, optind=%d, optarg=%s, opt_idx=%d\n", c, optopt, optind, optarg, opt_idx); 28 | switch (c) { 29 | case 0: 30 | printf("long option %s", options[opt_idx].name); 31 | if (optarg) { printf(" with arg %s", optarg); } 32 | printf("\n"); 33 | break; 34 | 35 | case 1: 36 | printf("non-option argument %s\n", optarg); 37 | break; 38 | 39 | case 'c': 40 | printf("Option %c with arg %s\n", c, optarg); 41 | config_id = atoi(optarg); 42 | break; 43 | 44 | case 'h': 45 | printf("Usage: %s [--help|--config |--create [opt_id]] [-c |-h]\n", argv[0]); 46 | break; 47 | 48 | case '?': 49 | printf("Unknown option %c\n", optopt); 50 | break; 51 | 52 | case ':': 53 | printf("Missing argument for %c\n", optopt); 54 | break; 55 | 56 | default: 57 | break; 58 | } 59 | } 60 | 61 | printf("config_id=%d, should_create=%d\n", config_id, should_create); 62 | printf("Remained args\n"); 63 | while (optind < argc) { 64 | printf("%s\n", argv[optind]); 65 | ++optind; 66 | } 67 | } -------------------------------------------------------------------------------- /examples/lecture2/021_simple_cond_variables.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | pthread_mutex_t mutex; // mutex for value change protection 8 | pthread_cond_t cond; // conditional variable for communication 9 | int value; // protected value 10 | } data_t; 11 | 12 | // common object: mutex and conditional variable 13 | // static initialization 14 | data_t data = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0}; 15 | 16 | void *thread_routine(void *arg) { 17 | int errflag = pthread_mutex_lock(&data.mutex); 18 | if (errflag != 0) { 19 | // ... 20 | } 21 | data.value = 1; // change value 22 | // send signal about value change 23 | errflag = pthread_cond_signal(&data.cond); 24 | if (errflag != 0) { 25 | // ... 26 | } 27 | errflag = pthread_mutex_unlock(&data.mutex); 28 | if (errflag != 0) { 29 | // ... 30 | } 31 | return arg; // another variant: return NULL etc 32 | } 33 | 34 | int main(int argc, char *argv[]) { 35 | int errflag = 0; 36 | struct timespec timeout; 37 | pthread_t thread; 38 | errflag = pthread_create(&thread, NULL, thread_routine, NULL); 39 | if (errflag != 0) { 40 | // ... 41 | } 42 | timeout.tv_sec = time(NULL) + 1; 43 | timeout.tv_nsec = 0; 44 | 45 | // blocking thread on conditional variable 46 | // requires prior mutex lock 47 | errflag = pthread_mutex_lock(&data.mutex); 48 | if (errflag != 0) { 49 | // ... 50 | } 51 | while (data.value == 0) { // first predicate check 52 | errflag = pthread_cond_timedwait(&data.cond, &data.mutex, &timeout); 53 | if (errflag == ETIMEDOUT) { 54 | break; // unlocking by timeout 55 | } 56 | else { 57 | // error on pthread_cond_timedwait call 58 | } 59 | } 60 | if (data.value != 0) { // second predicate check 61 | // ... 62 | } 63 | 64 | errflag = pthread_mutex_unlock(&data.mutex); 65 | if (errflag != 0) { 66 | // ... 67 | } 68 | errflag = pthread_join(thread, NULL); 69 | if (errflag != 0) { 70 | // ... 71 | } 72 | printf("result value: %d\n", data.value); 73 | return EXIT_SUCCESS; 74 | } 75 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/027_RTTI.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | namespace RTTI { 6 | class A { 7 | public: 8 | A() { std::cout << "ctor A()" << std::endl; } 9 | 10 | virtual void foo() { std::cout << std::endl << std::endl; } 11 | 12 | int a = 0; 13 | int b = 0; 14 | }; 15 | 16 | class B : public A { 17 | public: 18 | B() { std::cout << "ctor A()" << std::endl; } 19 | }; 20 | 21 | class C { 22 | public: 23 | C() = default; 24 | virtual void foo() {} 25 | }; 26 | 27 | 28 | void foo(A &a) { 29 | try { 30 | B &beta = dynamic_cast(a); 31 | } 32 | catch(std::bad_cast) { 33 | std::cout << "bad cast"; 34 | } 35 | } 36 | 37 | } // namespace diamond_problem 38 | 39 | 40 | 41 | int main() { 42 | using namespace RTTI; 43 | { 44 | A *a = new B; 45 | if (B *b = dynamic_cast(a)) { 46 | // успешно… 47 | std::cout << "b is a child of A"; 48 | } else { 49 | std::cout << "b is not a child of A"; 50 | } 51 | } 52 | std::cout << std::endl; 53 | { 54 | C *c = new C; 55 | if (B *b = dynamic_cast(c)) { 56 | // успешно… 57 | std::cout << "b is a child of C"; 58 | } else { 59 | std::cout << "b is not a child of C"; 60 | } 61 | } 62 | std::cout << std::endl; 63 | { 64 | B a; 65 | foo(a); 66 | } 67 | std::cout << std::endl; 68 | { 69 | A *a = new A; 70 | A *b = new B; 71 | if(typeid(a) == typeid(A*)) { 72 | std::cout << "a is A*" << std::endl; 73 | } 74 | 75 | if(typeid(*a) == typeid(A)) { 76 | std::cout << "*a is A" << std::endl; 77 | } 78 | 79 | if(typeid(b) == typeid(B*)) { 80 | std::cout << "b is B*" << std::endl; 81 | } 82 | } 83 | 84 | { 85 | struct Base {}; // non-polymorphic 86 | struct Derived : Base {}; 87 | 88 | struct Base2 { virtual void foo() {} }; // polymorphic 89 | struct Derived2 : Base2 {}; 90 | 91 | Derived d1; 92 | Base& b1 = d1; 93 | std::cout << "reference to non-polymorphic base: " << typeid(b1).name() << '\n'; 94 | 95 | Derived2 d2; 96 | Base2& b2 = d2; 97 | std::cout << "reference to polymorphic base: " << typeid(b2).name() << '\n'; 98 | } 99 | 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /examples/lecture2/020_mutex_trylock_bench.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define NUM_THREADS 10 7 | #define LOOPS 100000 8 | #define RETRIES 100 9 | 10 | int counter = 0; 11 | pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 12 | 13 | // using pthread_mutex_lock 14 | void *lock_worker(void *arg) { 15 | for (size_t i = 0; i < LOOPS; ++i) { 16 | pthread_mutex_lock(&mutex); 17 | ++counter; 18 | pthread_mutex_unlock(&mutex); 19 | } 20 | return arg; 21 | } 22 | 23 | // using try_lock - obviously only use one at a time 24 | void *trylock_worker(void *arg) { 25 | for (size_t i = 0; i < LOOPS; ++i) { 26 | while (pthread_mutex_trylock(&mutex) != 0) { 27 | // wait - threated as spin lock in this example 28 | } 29 | ++counter; 30 | pthread_mutex_unlock(&mutex); 31 | } 32 | return arg; 33 | } 34 | 35 | void bench(void (*f)(void)) { 36 | clock_t begin = clock(); 37 | 38 | for (size_t i = 0; i < RETRIES; ++i) { 39 | f(); 40 | } 41 | 42 | clock_t end = clock(); 43 | double time = (double)(end - begin) / CLOCKS_PER_SEC; 44 | double avg_time = time / RETRIES; 45 | 46 | printf("Average time spent: %f\n", avg_time); 47 | 48 | } 49 | 50 | void bench_lock_workers() { 51 | pthread_t t[NUM_THREADS]; 52 | int result = 0; 53 | 54 | counter = 0; 55 | for (size_t i = 0; i < NUM_THREADS; ++i) { 56 | result = pthread_create(&t[i], NULL, lock_worker, NULL); 57 | if (result) { 58 | printf("Thread #%d failed\n", (int)i); 59 | } 60 | } 61 | 62 | for (size_t i = 0; i < NUM_THREADS; ++i) { 63 | pthread_join(t[i], NULL); 64 | } 65 | 66 | //printf("%d\n", counter); 67 | } 68 | 69 | void bench_trylock_workers() { 70 | pthread_t t[NUM_THREADS]; 71 | int result = 0; 72 | 73 | counter = 0; 74 | for (size_t i = 0; i < NUM_THREADS; ++i) { 75 | result = pthread_create(&t[i], NULL, trylock_worker, NULL); 76 | if (result) { 77 | printf("Thread #%d failed\n", (int)i); 78 | } 79 | } 80 | 81 | for (size_t i = 0; i < NUM_THREADS; ++i) { 82 | pthread_join(t[i], NULL); 83 | } 84 | 85 | //printf("%d\n", counter); 86 | } 87 | 88 | int main(int argc, char *argv[]) { 89 | printf("Benchmarking lock workers...\n"); 90 | bench(bench_lock_workers); 91 | printf("Benchmarking trylock workers...\n"); 92 | bench(bench_trylock_workers); 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(examples) 3 | 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -Wall -ggdb3") 8 | 9 | 10 | add_executable(001_encapsulation 001_encapsulation.cpp) 11 | add_executable(002_namespaces 002_namespaces.cpp) 12 | add_executable(003_initialization_without_constructor 003_initialization_without_constructor.cpp) 13 | add_executable(004_default_contructor 004_default_contructor.cpp) 14 | add_executable(005_required_default_constructor_for_array 005_required_default_constructor_for_array.cpp) 15 | add_executable(006_constructor_with_one_argument 006_constructor_with_one_argument.cpp) 16 | 17 | add_executable(007_private_constructor 007_private_constructor.cpp) 18 | add_executable(008_default_copy_constructor_and_assign_operator 008_default_copy_constructor_and_assign_operator.cpp) 19 | add_executable(009_transform_constuctors_and_operations 009_transform_constuctors_and_operations.cpp) 20 | add_executable(010_initializer_list_vs_constructor_body 010_initializer_list_vs_constructor_body.cpp) 21 | 22 | add_executable(011_destructors 011_destructors.cpp) 23 | add_executable(012_placement_new 012_placement_new.cpp) 24 | add_executable(013_simple_initializers_in_cpp11 013_simple_initializers_in_cpp11.cpp) 25 | add_executable(014_move_constructor 014_move_constructor.cpp) 26 | add_executable(015_move_assignment 015_move_assignment.cpp) 27 | 28 | add_executable(016_assignment_via_constructor 016_assignment_via_constructor.cpp) 29 | add_executable(017_defaults_constructors 017_defaults_constructors.cpp) 30 | add_executable(018_trivial_constructors 018_trivial_constructors.cpp) 31 | add_executable(019_delete_and_default_methods 019_delete_and_default_methods.cpp) 32 | 33 | add_executable(020_RVO_NRVO 020_RVO_NRVO.cpp) 34 | add_executable(021_RAII 021_RAII.cpp) 35 | add_executable(022_undefined_sizeof 022_undefined_sizeof.cpp) 36 | add_executable(023_noexcept_destructor 023_noexcept_destructor.cpp) 37 | add_executable(024_using_conflicts 024_using_conflicts.cpp) 38 | add_executable(025_contr_order 025_contr_order.cpp) 39 | add_executable(026_dimond_inheritance 026_diamond_inheritance.cpp) 40 | add_executable(027_RTTI 027_RTTI.cpp) 41 | add_executable(028_elimination 028_elimination.cpp) 42 | add_executable(029_abstract_factory 029_abstract_factory.cpp) 43 | add_executable(030_adapter 030_adapter.cpp) 44 | add_executable(031_bridge 031_bridge.cpp) 45 | add_executable(032_command 032_command.cpp) 46 | add_executable(033_observer 033_observer.cpp) 47 | add_executable(034_visitor 034_visitor.cpp) 48 | 49 | 50 | -------------------------------------------------------------------------------- /examples/lecture2/014_messages_queue.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MAX_SEND_SIZE 80 11 | #define PROCESSES_COUNT 10 12 | 13 | struct mymsgbuf { 14 | long mtype; 15 | char mtext[MAX_SEND_SIZE]; 16 | }; 17 | 18 | void send_message(int qid, struct mymsgbuf *qbuf, long type, char *text) { 19 | qbuf->mtype = type; 20 | strcpy(qbuf->mtext, text); 21 | if (msgsnd(qid, (struct msgbuf *)qbuf, strlen(qbuf->mtext) + 1, 0) == -1) { 22 | printf("Failed to send message\n"); 23 | } 24 | } 25 | 26 | void read_message(int qid, struct mymsgbuf *qbuf, long type) { 27 | qbuf->mtype = type; 28 | if (msgrcv(qid, (struct msgbuf *)qbuf, MAX_SEND_SIZE, type, 0) < 0) { 29 | printf("Failed to read message from queue\n"); 30 | } else { 31 | printf("Received %s\n", qbuf->mtext); 32 | } 33 | } 34 | 35 | int main() { 36 | int qtype = 1, pid[PROCESSES_COUNT], msgqid; 37 | struct mymsgbuf qbuf; 38 | 39 | key_t key = ftok("014_messages_queue.c", 'b'); 40 | if (key == -1) { 41 | perror("Failed to create key\n"); 42 | return 1; 43 | } 44 | printf("Created key %d\n", key); 45 | 46 | if ((msgqid = msgget(key, IPC_CREAT|0660)) == -1) { 47 | perror("Failed to create queue\n"); 48 | return 1; 49 | } 50 | 51 | /* 52 | // можно ещё создать идентификатор очереди автоматически с помощью ОС 53 | if ((msgqid = msgget(IPC_PRIVATE, IPC_CREAT|0660)) == -1) { 54 | perror("Failed to create queue\n"); 55 | return 1; 56 | } 57 | */ 58 | 59 | for (int i = 1; i < PROCESSES_COUNT; ++i) { 60 | pid[i] = fork(); 61 | if (pid[i] == -1) { 62 | printf("Failed to create process\n"); 63 | continue; 64 | } 65 | 66 | if (pid[i] == 0) { 67 | char str[40]; 68 | sprintf(str, "Hello world from %d", getpid()); 69 | send_message(msgqid, &qbuf, qtype, str); 70 | exit(0); 71 | } 72 | } 73 | 74 | for (int stat, i = 1; i < PROCESSES_COUNT; ++i) { 75 | int status = waitpid(pid[i], &stat, 0); 76 | if (pid[i] == status) { 77 | printf("Child process %d exited\n", pid[i]); 78 | } 79 | } 80 | 81 | for (int i = 1; i < PROCESSES_COUNT; ++i) { 82 | read_message(msgqid, &qbuf, qtype); 83 | } 84 | 85 | if (msgctl(msgqid, IPC_RMID, NULL) < 0) { 86 | printf("Failed to remove queue\n"); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/032_command.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | struct Document { 8 | void insert() { 9 | std::cout << "insert command\n"; 10 | } 11 | void remove(){ 12 | std::cout << "remove command\n"; 13 | } 14 | void copy(){ 15 | std::cout << "copy command\n"; 16 | } 17 | }; 18 | 19 | struct Command { 20 | explicit Command(Document* doc) : doc_(doc) {} 21 | virtual void execute() = 0; 22 | virtual void custom_execute() {}; 23 | 24 | protected: 25 | Document* doc_; 26 | }; 27 | 28 | struct CopyCommand : public Command { 29 | explicit CopyCommand(Document* doc) : Command(doc) {} 30 | void execute() { 31 | doc_->copy(); 32 | } 33 | }; 34 | 35 | struct RemoveCommand : public Command { 36 | explicit RemoveCommand(Document* doc) : Command(doc) {} 37 | void execute() { 38 | doc_->remove(); 39 | } 40 | }; 41 | 42 | struct CustomCommand : public Command { 43 | using ExCommand = std::function; 44 | using AnyCommand = std::function; 45 | 46 | explicit CustomCommand(Document *doc, ExCommand command) 47 | : Command(doc), command_(command) { 48 | } 49 | 50 | explicit CustomCommand(AnyCommand command) 51 | : Command(nullptr), any_command_(command) {} 52 | 53 | void execute() override { 54 | command_(*doc_); 55 | } 56 | 57 | void custom_execute() override { 58 | any_command_(); 59 | } 60 | 61 | ExCommand command_; 62 | AnyCommand any_command_; 63 | }; 64 | 65 | // -------------------------------- 66 | 67 | struct CopyButton { 68 | void setCommand(Command *command) { 69 | command_ = command; 70 | } 71 | 72 | void onClick() { 73 | command_->execute(); 74 | } 75 | 76 | private: 77 | Command *command_; 78 | }; 79 | 80 | int main() { 81 | Document doc; 82 | Command* copyCommand = new CopyCommand(&doc); 83 | 84 | CopyButton btn; 85 | btn.setCommand(copyCommand); 86 | btn.onClick(); 87 | 88 | { 89 | std::cout << "Custom command \n"; 90 | 91 | Document doc; 92 | 93 | 94 | std::function copy_function = std::bind(&Document::copy, 95 | std::placeholders::_1); 96 | 97 | std::function copy_function2 = std::bind(&Document::copy, &doc); 98 | 99 | // 100 | // 101 | copy_function(doc); 102 | copy_function2(); 103 | 104 | { 105 | CustomCommand custom_command(&doc, copy_function); 106 | custom_command.execute(); 107 | } 108 | 109 | { 110 | CustomCommand custom_command(copy_function2); 111 | custom_command.custom_execute(); 112 | } 113 | } 114 | 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /2017_2/examples/patterns/032_command.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | struct Document { 8 | void insert() { 9 | std::cout << "insert command\n"; 10 | } 11 | void remove(){ 12 | std::cout << "remove command\n"; 13 | } 14 | void copy(){ 15 | std::cout << "copy command\n"; 16 | } 17 | }; 18 | 19 | struct Command { 20 | explicit Command(Document* doc) : doc_(doc) {} 21 | virtual void execute() = 0; 22 | virtual void custom_execute() {}; 23 | 24 | protected: 25 | Document* doc_; 26 | }; 27 | 28 | struct CopyCommand : public Command { 29 | explicit CopyCommand(Document* doc) : Command(doc) {} 30 | void execute() { 31 | doc_->copy(); 32 | } 33 | }; 34 | 35 | struct RemoveCommand : public Command { 36 | explicit RemoveCommand(Document* doc) : Command(doc) {} 37 | void execute() { 38 | doc_->remove(); 39 | } 40 | }; 41 | 42 | struct CustomCommand : public Command { 43 | using ExCommand = std::function; 44 | using AnyCommand = std::function; 45 | 46 | explicit CustomCommand(Document *doc, ExCommand command) 47 | : Command(doc), command_(command) { 48 | } 49 | 50 | explicit CustomCommand(AnyCommand command) 51 | : Command(nullptr), any_command_(command) {} 52 | 53 | void execute() override { 54 | command_(*doc_); 55 | } 56 | 57 | void custom_execute() override { 58 | any_command_(); 59 | } 60 | 61 | ExCommand command_; 62 | AnyCommand any_command_; 63 | }; 64 | 65 | // -------------------------------- 66 | 67 | struct CopyButton { 68 | void setCommand(Command *command) { 69 | command_ = command; 70 | } 71 | 72 | void onClick() { 73 | command_->execute(); 74 | } 75 | 76 | private: 77 | Command *command_; 78 | }; 79 | 80 | int main() { 81 | Document doc; 82 | Command* copyCommand = new CopyCommand(&doc); 83 | 84 | CopyButton btn; 85 | btn.setCommand(copyCommand); 86 | btn.onClick(); 87 | 88 | { 89 | std::cout << "Custom command \n"; 90 | 91 | Document doc; 92 | 93 | 94 | std::function copy_function = std::bind(&Document::copy, 95 | std::placeholders::_1); 96 | 97 | std::function copy_function2 = std::bind(&Document::copy, &doc); 98 | 99 | // 100 | // 101 | copy_function(doc); 102 | copy_function2(); 103 | 104 | { 105 | CustomCommand custom_command(&doc, copy_function); 106 | custom_command.execute(); 107 | } 108 | 109 | { 110 | CustomCommand custom_command(copy_function2); 111 | custom_command.custom_execute(); 112 | } 113 | } 114 | 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /examples_gdb/calc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char peek_not_eof(std::FILE* in) 5 | { 6 | char c = std::getc(in); 7 | if (std::feof(in) || c == '\n') 8 | return '\0'; 9 | std::ungetc(c, in); 10 | return c; 11 | } 12 | 13 | void drop_char(std::FILE* in) 14 | { 15 | std::getc(in); 16 | } 17 | 18 | enum retcode_t { 19 | E_OK, 20 | E_EOF, 21 | E_INVAL 22 | }; 23 | 24 | retcode_t eval_primary(std::FILE* in, double* value) 25 | { 26 | bool negate = false; 27 | while (char sgn = peek_not_eof(in)) { 28 | if (sgn != '-') 29 | break; 30 | negate = !negate; 31 | drop_char(in); 32 | } 33 | 34 | bool seen_digit = false; 35 | double cur_val = 0; 36 | while (char c = peek_not_eof(in)) { 37 | if (!(c >= '0' && c <= '9')) 38 | break; 39 | seen_digit = true; 40 | cur_val = cur_val * 10 + (c - '0'); 41 | drop_char(in); 42 | } 43 | if (!seen_digit) 44 | return E_EOF; 45 | *value = negate ? -cur_val : cur_val; 46 | return E_OK; 47 | } 48 | 49 | retcode_t eval_term(std::FILE* in, double* value) 50 | { 51 | double prim; 52 | retcode_t rc = eval_primary(in, &prim); 53 | if (rc != E_OK) 54 | return rc; 55 | 56 | double cur_value = prim; 57 | while (char op = peek_not_eof(in)) { 58 | if (op != '*') 59 | break; 60 | drop_char(in); 61 | 62 | rc = eval_primary(in, &prim); 63 | if (rc != E_OK) 64 | return rc; 65 | cur_value *= prim; 66 | } 67 | 68 | *value = cur_value; 69 | return E_OK; 70 | } 71 | 72 | retcode_t eval_expr(std::FILE* in, double* value) 73 | { 74 | double term; 75 | retcode_t rc = eval_term(in, &term); 76 | if (rc != E_OK) 77 | return rc; 78 | 79 | double cur_value = term; 80 | while (char op = peek_not_eof(in)) { 81 | if (!(op == '+' || op == '-')) 82 | return E_INVAL; 83 | drop_char(in); 84 | 85 | rc = eval_term(in, &term); 86 | if (rc != E_OK) 87 | return rc; 88 | 89 | if (op == '+') 90 | cur_value += term; 91 | else 92 | cur_value -= term; 93 | } 94 | 95 | *value = cur_value; 96 | return E_OK; 97 | } 98 | 99 | int main() 100 | { 101 | double result; 102 | retcode_t rc = eval_expr(stdin, &result); 103 | switch (rc) { 104 | case E_OK: 105 | std::printf("%10lf\n", result); 106 | break; 107 | case E_EOF: 108 | std::printf("ERROR. Unexpected end of input\n"); 109 | break; 110 | case E_INVAL: 111 | std::printf("ERROR. Invalid expression\n"); 112 | break; 113 | } 114 | return 0; 115 | } 116 | -------------------------------------------------------------------------------- /examples_gdb/calc_fixed.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char peek_not_eof(std::FILE* in) 5 | { 6 | char c = std::getc(in); 7 | if (std::feof(in) || c == '\n') 8 | return '\0'; 9 | std::ungetc(c, in); 10 | return c; 11 | } 12 | 13 | void drop_char(std::FILE* in) 14 | { 15 | std::getc(in); 16 | } 17 | 18 | enum retcode_t { 19 | E_OK, 20 | E_EOF, 21 | E_INVAL 22 | }; 23 | 24 | retcode_t eval_primary(std::FILE* in, double* value) 25 | { 26 | bool negate = false; 27 | while (char sgn = peek_not_eof(in)) { 28 | if (sgn != '-') 29 | break; 30 | negate = !negate; 31 | drop_char(in); 32 | } 33 | 34 | bool seen_digit = false; 35 | double cur_val = 0; 36 | while (char c = peek_not_eof(in)) { 37 | if (!(c >= '0' && c <= '9')) { 38 | if (!seen_digit) 39 | return E_INVAL; 40 | break; 41 | } 42 | seen_digit = true; 43 | cur_val = cur_val * 10 + (c - '0'); 44 | drop_char(in); 45 | } 46 | if (!seen_digit) 47 | return E_EOF; 48 | *value = negate ? -cur_val : cur_val; 49 | return E_OK; 50 | } 51 | 52 | retcode_t eval_term(std::FILE* in, double* value) 53 | { 54 | double prim; 55 | retcode_t rc = eval_primary(in, &prim); 56 | if (rc != E_OK) 57 | return rc; 58 | 59 | double cur_value = prim; 60 | while (char op = peek_not_eof(in)) { 61 | if (op != '*') 62 | break; 63 | drop_char(in); 64 | 65 | rc = eval_primary(in, &prim); 66 | if (rc != E_OK) 67 | return rc; 68 | cur_value *= prim; 69 | } 70 | 71 | *value = cur_value; 72 | return E_OK; 73 | } 74 | 75 | retcode_t eval_expr(std::FILE* in, double* value) 76 | { 77 | double term; 78 | retcode_t rc = eval_term(in, &term); 79 | if (rc != E_OK) 80 | return rc; 81 | 82 | double cur_value = term; 83 | while (char op = peek_not_eof(in)) { 84 | if (!(op == '+' || op == '-')) 85 | return E_INVAL; 86 | drop_char(in); 87 | 88 | rc = eval_term(in, &term); 89 | if (rc != E_OK) 90 | return rc; 91 | 92 | if (op == '+') 93 | cur_value += term; 94 | else 95 | cur_value -= term; 96 | } 97 | 98 | *value = cur_value; 99 | return E_OK; 100 | } 101 | 102 | int main() 103 | { 104 | double result; 105 | retcode_t rc = eval_expr(stdin, &result); 106 | switch (rc) { 107 | case E_OK: 108 | std::printf("%10lf\n", result); 109 | break; 110 | case E_EOF: 111 | std::printf("ERROR. Unexpected end of input\n"); 112 | break; 113 | case E_INVAL: 114 | std::printf("ERROR. Invalid expression\n"); 115 | break; 116 | } 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /examples/lecture1/003_size_t_and_ptrdiff_t_types.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // ptrdiff_t 4 | #include 5 | 6 | size_t find_max(size_t *first, size_t *last) { 7 | ptrdiff_t elements_count = last - first; 8 | if (elements_count <= 0) { 9 | return 0; 10 | } 11 | size_t max = *first; 12 | for (size_t i = 1; i < elements_count; ++i) { 13 | if (first[i] > max) { 14 | max = first[i]; 15 | } 16 | } 17 | return max; 18 | } 19 | 20 | int main(int argc, char *argv[]) { 21 | // Incorrect use 22 | printf("Incorrect working via pointer with incoming data\n"); 23 | size_t total_size = sizeof argv; // wrong answer: got pointer, not static array 24 | size_t element_size = sizeof argv[0]; 25 | size_t elements_count = total_size / element_size; 26 | printf("Expected: %d (argc), found: %ld (sizeof) arguments\n", argc, elements_count); 27 | for (size_t i = 0; i < elements_count; ++i) { 28 | printf("%s\n", argv[i]); 29 | } 30 | 31 | // Incorrect use 32 | printf("Incorrect working with dynamically allocated array via pointer\n"); 33 | const int N = 10; 34 | int *dyn_arr = (int *)malloc(N * sizeof(int)); 35 | total_size = sizeof dyn_arr; 36 | element_size = sizeof dyn_arr[0]; 37 | elements_count = total_size / element_size; 38 | printf("Found %ld array elements\n", elements_count); 39 | free(dyn_arr); 40 | 41 | // Correct use 42 | printf("Working with statically allocated array\n"); 43 | size_t arr[N]; 44 | total_size = sizeof(arr); 45 | element_size = sizeof(arr[0]); 46 | elements_count = total_size / element_size; 47 | printf("Found %ld array elements\n", elements_count); 48 | 49 | // Another way to find array size 50 | ptrdiff_t elements_between = &arr[N] - arr; 51 | printf("Found %d array elements via ptrdiff_t\n", elements_between); 52 | 53 | srand(time(NULL)); 54 | printf("Random array: \n"); 55 | for (size_t i = 0; i < elements_between; ++i) { 56 | arr[i] = rand() % 10; 57 | printf("%ld ", arr[i]); 58 | } 59 | printf("\n"); 60 | printf("correct: %ld\n", find_max(arr, &arr[N])); 61 | printf("incorrect: %ld\n", find_max(&arr[N], arr)); 62 | 63 | // Incorrect diff 64 | char char_arr[N]; 65 | printf("sizeof size_t is %ld\n", sizeof(size_t)); 66 | ptrdiff_t char_less_than_one_diff = &char_arr[sizeof(size_t) - 1] - &char_arr[0]; 67 | ptrdiff_t size_t_less_than_one_diff = (size_t *)&char_arr[sizeof(size_t) - 1] - (size_t *)&char_arr[0]; 68 | printf("size_t_less_than_one_diff: %d (char is %d)\n", size_t_less_than_one_diff, char_less_than_one_diff); 69 | ptrdiff_t char_more_than_one_diff = &char_arr[sizeof(size_t) + 1] - &char_arr[0]; 70 | ptrdiff_t size_t_more_than_one_diff = (size_t *)&char_arr[sizeof(size_t) + 1] - (size_t *)&char_arr[0]; 71 | printf("size_t_more_than_one_diff: %d (char is %d)\n", size_t_more_than_one_diff, char_more_than_one_diff); 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /2017_2/examples/lecture3/034_visitor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | struct Visitor; 7 | 8 | struct Building { 9 | virtual void accept(Visitor* visitor) = 0; 10 | }; 11 | 12 | 13 | struct City : public Building { 14 | void accept(Visitor* visitor) override; 15 | }; 16 | struct Industry : public Building { 17 | void accept(Visitor* visitor) override; 18 | }; 19 | struct House : public Building { 20 | void accept(Visitor* visitor) override; 21 | }; 22 | 23 | 24 | struct Visitor { 25 | virtual void visit(City& ref) = 0; 26 | virtual void visit(Industry& ref) = 0; 27 | virtual void visit(House &ref) = 0; 28 | 29 | 30 | virtual void visit2(City* c) = 0; 31 | virtual void visit2(Industry* f) = 0; 32 | virtual void visit2(House* h) = 0; 33 | 34 | virtual ~Visitor() = default; 35 | }; 36 | 37 | class ExportVisitor : public Visitor { 38 | void doForCity(City c) {} 39 | void doForIndustry(Industry f) {} 40 | void doForHouse(House h) {} 41 | }; 42 | 43 | /* 44 | ExportVisitor visitor; 45 | for (Building* building: buildings) { 46 | if(auto building = dynamic_cast(Building)) { 47 | // do something for City 48 | visitor.doForCity(*building); 49 | } else if (auto building = dynamic_cast(Building)) { 50 | // do something for Industry 51 | visitor.doForIndustry(*building); 52 | } 53 | } 54 | */ 55 | 56 | /*********************************************************************************/ 57 | 58 | void City::accept(Visitor *visitor) { 59 | visitor->visit(*this); 60 | visitor->visit2(this); 61 | } 62 | 63 | void Industry::accept(Visitor *visitor) { 64 | visitor->visit(*this); 65 | visitor->visit2(this); 66 | } 67 | void House::accept(Visitor *visitor) { 68 | visitor->visit(*this); 69 | visitor->visit2(this); 70 | } 71 | 72 | struct BuildingVisitor : public Visitor { 73 | void visit(City &ref) override { std::cout << "City visited\n"; }; 74 | void visit(Industry &ref) override { std::cout << "Industry visited\n"; }; 75 | void visit(House &ref) override { std::cout << "House visited\n"; }; 76 | 77 | void visit2(City *c) override { std::cout << "City*\n"; } 78 | void visit2(Industry *f) override { std::cout << "Industry*\n"; } 79 | void visit2(House *h) override { std::cout << "House*\n"; } 80 | }; 81 | 82 | struct ExportVisitor2 { 83 | void doForBuilding(Building* c) { std::cout << "Building*\n"; } 84 | void doForBuilding(City* c) { std::cout << "City*\n"; } 85 | void doForIndustry(Industry* f) { std::cout << "Industry*\n"; } 86 | void doForHouse(House h) { std::cout << "House*\n"; } 87 | }; 88 | 89 | 90 | // -------------------------------- 91 | int main() { 92 | // { 93 | // ExportVisitor2 visitor; 94 | // Building* building = new City(); 95 | // for (auto : ) 96 | // visitor.doForBuilding(building); 97 | // } 98 | 99 | { 100 | City city; 101 | House house; 102 | Industry industry; 103 | Building *buildings[] = {&city, &house, &industry}; 104 | for (auto building : buildings) { 105 | BuildingVisitor visitor; 106 | building->accept(&visitor); 107 | } 108 | } 109 | 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /2017_2/examples/patterns/034_visitor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | struct Visitor; 7 | 8 | struct Building { 9 | virtual void accept(Visitor* visitor) = 0; 10 | }; 11 | 12 | 13 | struct City : public Building { 14 | void accept(Visitor* visitor) override; 15 | }; 16 | struct Industry : public Building { 17 | void accept(Visitor* visitor) override; 18 | }; 19 | struct House : public Building { 20 | void accept(Visitor* visitor) override; 21 | }; 22 | 23 | 24 | struct Visitor { 25 | virtual void visit(City& ref) = 0; 26 | virtual void visit(Industry& ref) = 0; 27 | virtual void visit(House &ref) = 0; 28 | 29 | 30 | virtual void visit2(City* c) = 0; 31 | virtual void visit2(Industry* f) = 0; 32 | virtual void visit2(House* h) = 0; 33 | 34 | virtual ~Visitor() = default; 35 | }; 36 | 37 | class ExportVisitor : public Visitor { 38 | void doForCity(City c) {} 39 | void doForIndustry(Industry f) {} 40 | void doForHouse(House h) {} 41 | }; 42 | 43 | /* 44 | ExportVisitor visitor; 45 | for (Building* building: buildings) { 46 | if(auto building = dynamic_cast(Building)) { 47 | // do something for City 48 | visitor.doForCity(*building); 49 | } else if (auto building = dynamic_cast(Building)) { 50 | // do something for Industry 51 | visitor.doForIndustry(*building); 52 | } 53 | } 54 | */ 55 | 56 | /*********************************************************************************/ 57 | 58 | void City::accept(Visitor *visitor) { 59 | visitor->visit(*this); 60 | visitor->visit2(this); 61 | } 62 | 63 | void Industry::accept(Visitor *visitor) { 64 | visitor->visit(*this); 65 | visitor->visit2(this); 66 | } 67 | void House::accept(Visitor *visitor) { 68 | visitor->visit(*this); 69 | visitor->visit2(this); 70 | } 71 | 72 | struct BuildingVisitor : public Visitor { 73 | void visit(City &ref) override { std::cout << "City visited\n"; }; 74 | void visit(Industry &ref) override { std::cout << "Industry visited\n"; }; 75 | void visit(House &ref) override { std::cout << "House visited\n"; }; 76 | 77 | void visit2(City *c) override { std::cout << "City*\n"; } 78 | void visit2(Industry *f) override { std::cout << "Industry*\n"; } 79 | void visit2(House *h) override { std::cout << "House*\n"; } 80 | }; 81 | 82 | struct ExportVisitor2 { 83 | void doForBuilding(Building* c) { std::cout << "Building*\n"; } 84 | void doForBuilding(City* c) { std::cout << "City*\n"; } 85 | void doForIndustry(Industry* f) { std::cout << "Industry*\n"; } 86 | void doForHouse(House h) { std::cout << "House*\n"; } 87 | }; 88 | 89 | 90 | // -------------------------------- 91 | int main() { 92 | // { 93 | // ExportVisitor2 visitor; 94 | // Building* building = new City(); 95 | // for (auto : ) 96 | // visitor.doForBuilding(building); 97 | // } 98 | 99 | { 100 | City city; 101 | House house; 102 | Industry industry; 103 | Building *buildings[] = {&city, &house, &industry}; 104 | for (auto building : buildings) { 105 | BuildingVisitor visitor; 106 | building->accept(&visitor); 107 | } 108 | } 109 | 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /examples/lecture2/017_lock_mutex_deadlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | int balance; 8 | pthread_mutex_t balance_mutex; 9 | } bank_account; 10 | 11 | typedef struct { 12 | bank_account *from; 13 | bank_account *to; 14 | int amount; 15 | } deposit_thr_args; 16 | 17 | void create_bank_account(bank_account **ba, int initial_amount) { 18 | int result = 0; 19 | bank_account *nba = (bank_account *)malloc(sizeof(bank_account)); 20 | if (nba == NULL) { 21 | /* Handle error */ 22 | } 23 | 24 | nba->balance = initial_amount; 25 | result = pthread_mutex_init(&nba->balance_mutex, NULL); 26 | if (result) { 27 | /* Handle error */ 28 | } 29 | 30 | *ba = nba; 31 | } 32 | 33 | void *deposit(void *ptr) { 34 | int result = 0; 35 | deposit_thr_args *args = (deposit_thr_args *)ptr; 36 | 37 | printf("FROM: %p, BEFORE LOCKING %p\n", args->from, args->from); 38 | if ((result = pthread_mutex_lock(&(args->from->balance_mutex))) != 0) { 39 | /* Handle error */ 40 | } 41 | printf("FROM: %p, AFTER LOCKING %p\n", args->from, args->from); 42 | 43 | sleep(2); 44 | /* Not enough balance to transfer */ 45 | if (args->from->balance < args->amount) { 46 | printf("FROM: %p, BEFORE UNLOCKING %p\n", args->from, args->from); 47 | if ((result = pthread_mutex_unlock(&(args->from->balance_mutex))) != 0) { 48 | /* Handle error */ 49 | } 50 | printf("FROM: %p, AFTER UNLOCKING %p\n", args->from, args->from); 51 | return NULL; 52 | } 53 | 54 | printf("FROM: %p, BEFORE LOCKING %p\n", args->from, args->to); 55 | if ((result = pthread_mutex_lock(&(args->to->balance_mutex))) != 0) { 56 | /* Handle error */ 57 | } 58 | printf("FROM: %p, AFTER LOCKING %p\n", args->from, args->to); 59 | 60 | args->from->balance -= args->amount; 61 | args->to->balance += args->amount; 62 | 63 | printf("FROM: %p, BEFORE UNLOCKING %p\n", args->from, args->from); 64 | if ((result = pthread_mutex_unlock(&(args->from->balance_mutex))) != 0) { 65 | /* Handle error */ 66 | } 67 | printf("FROM: %p, AFTER UNLOCKING %p\n", args->from, args->from); 68 | printf("FROM: %p, BEFORE UNLOCKING %p\n", args->from, args->to); 69 | if ((result = pthread_mutex_unlock(&(args->to->balance_mutex))) != 0) { 70 | /* Handle error */ 71 | } 72 | printf("FROM: %p, AFTER UNLOCKING %p\n", args->from, args->to); 73 | 74 | free(ptr); 75 | return NULL; 76 | } 77 | 78 | int main(int argc, char *argv[]) { 79 | pthread_t thr1, thr2; 80 | int result = 0; 81 | 82 | bank_account *ba1 = NULL; 83 | bank_account *ba2 = NULL; 84 | create_bank_account(&ba1, 1000); 85 | create_bank_account(&ba2, 1000); 86 | 87 | deposit_thr_args *arg1 = (deposit_thr_args *)malloc(sizeof(deposit_thr_args)); 88 | if (arg1 == NULL) { 89 | /* Handle error */ 90 | } 91 | deposit_thr_args *arg2 = (deposit_thr_args *)malloc(sizeof(deposit_thr_args)); 92 | if (arg2 == NULL) { 93 | /* Handle error */ 94 | } 95 | 96 | arg1->from = ba1; 97 | arg1->to = ba2; 98 | arg1->amount = 100; 99 | 100 | arg2->from = ba2; 101 | arg2->to = ba1; 102 | arg2->amount = 100; 103 | 104 | /* Perform the deposits */ 105 | if ((result = pthread_create(&thr1, NULL, deposit, (void *)arg1)) != 0) { 106 | /* Handle error */ 107 | } 108 | if ((result = pthread_create(&thr2, NULL, deposit, (void *)arg2)) != 0) { 109 | /* Handle error */ 110 | } 111 | 112 | pthread_exit(NULL); 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /examples/lecture3/007_private_constructor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class BadSingleton { 4 | private: 5 | static BadSingleton *_instance; 6 | int count; 7 | public: 8 | static BadSingleton *getInstance() { 9 | if (!_instance) { 10 | _instance = new BadSingleton(); 11 | } 12 | return _instance; 13 | } 14 | 15 | void inc() { 16 | ++count; 17 | } 18 | 19 | void print() { 20 | std::cout << _instance << " " << count << std::endl; 21 | } 22 | 23 | ~BadSingleton() { 24 | std::cout << "~BadSingleton()" << std::endl; 25 | _instance = NULL; 26 | } 27 | private: 28 | BadSingleton() : count(0) { 29 | std::cout << "BadSingleton()" << std::endl; 30 | } 31 | BadSingleton(const BadSingleton &s) { 32 | std::cout << "BadSingleton(const BadSingleton &s)" << std::endl; 33 | } 34 | BadSingleton &operator=(BadSingleton &s) { 35 | std::cout << "BadSingleton &operator=" << std::endl; 36 | return s; 37 | } 38 | }; 39 | 40 | BadSingleton *BadSingleton::_instance = NULL; 41 | 42 | class GoodSingleton { 43 | private: 44 | int count; 45 | public: 46 | static GoodSingleton &getInstance() { 47 | static GoodSingleton _instance; 48 | return _instance; 49 | } 50 | 51 | void inc() { 52 | ++count; 53 | } 54 | 55 | void print() { 56 | std::cout << count << std::endl; 57 | } 58 | private: 59 | GoodSingleton() : count(0) { 60 | std::cout << "GoodSingleton()" << std::endl; 61 | } 62 | GoodSingleton(const GoodSingleton &s) { 63 | std::cout << "GoodSingleton(const BetterSingleron &s)" << std::endl; 64 | } 65 | GoodSingleton &operator=(GoodSingleton &s) { 66 | std::cout << "GoodSingleton &operator=" << std::endl; 67 | return s; 68 | } 69 | ~GoodSingleton() { 70 | std::cout << "~GoodSingleton()" << std::endl; 71 | } 72 | }; 73 | 74 | class GoodSingleton; 75 | 76 | int main(int argc, char *argv[]) { 77 | //BadSingleton s1; 78 | BadSingleton *s11(BadSingleton::getInstance()); 79 | BadSingleton *s12 = BadSingleton::getInstance(); 80 | s11->inc(); 81 | s11->inc(); 82 | s11->inc(); 83 | s11->print(); 84 | s12->print(); 85 | s12->inc(); 86 | s12->inc(); 87 | s12->print(); 88 | s11->print(); 89 | BadSingleton::getInstance()->print(); 90 | delete BadSingleton::getInstance(); // not comfortable 91 | 92 | //GoodSingleton s2; 93 | GoodSingleton &s21 = GoodSingleton::getInstance(); 94 | GoodSingleton &s22(GoodSingleton::getInstance()); 95 | s21.inc(); 96 | s21.inc(); 97 | s21.inc(); 98 | s21.print(); 99 | s22.print(); 100 | s22.inc(); 101 | s22.inc(); 102 | s22.print(); 103 | s21.print(); 104 | GoodSingleton::getInstance().print(); 105 | return 0; 106 | } 107 | 108 | 109 | template 110 | class Singleton { 111 | public: 112 | static Type& GetInstance() { 113 | Type* instance = atomic_instance_.load(); 114 | if (!instance) { 115 | std::lock_guard lock(initialization_mutex_); 116 | instance = atomic_instance_.load(); 117 | if (!instance) { 118 | instance = new Type; 119 | atomic_instance_.store(instance); 120 | } 121 | } 122 | 123 | return *instance; 124 | } 125 | 126 | protected: 127 | Singleton() {} 128 | ~Singleton() {} 129 | 130 | private: 131 | static std::mutex initialization_mutex_; 132 | static std::atomic atomic_instance_; 133 | }; 134 | 135 | template 136 | std::mutex Singleton::initialization_mutex_; 137 | template 138 | std::atomic Singleton::atomic_instance_; -------------------------------------------------------------------------------- /examples/lecture2/022_watcher_cond_variables.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Описание: 3 | * Главный поток создаёт три потока. Два из них увеличивают 4 | * значение переменной count, в то время как третий тред 5 | * отслеживает значение этой переменной. Когда count 6 | * досгитает предопределённого лимита, ожидающий тред 7 | * получает сигнал от одного из инкрементирующих тредов? 8 | * Ожидающий тред просыпается и затем модифицирует count. 9 | * Программа продолжается до тех пор, пока count не станет 10 | * равным TCOUNT. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define NUM_THREADS 3 19 | #define TCOUNT 10 20 | #define COUNT_LIMIT 12 21 | 22 | int count = 0; 23 | pthread_mutex_t count_mutex; 24 | pthread_cond_t count_threshold_cv; 25 | 26 | void *inc_count(void *t) { 27 | int i; 28 | long my_id = (long)t; 29 | 30 | for (i = 0; i < TCOUNT; ++i) { 31 | pthread_mutex_lock(&count_mutex); 32 | ++count; 33 | 34 | /* 35 | * Проверяем значение переменной и посылаем сигнал 36 | * ожидающему треду, когда условие достигнуто. 37 | * Важно, что это происходит в то время, когда мьютекс заблокирован. 38 | */ 39 | if (count == COUNT_LIMIT) { 40 | printf("inc_count(): thread %ld, count = %d Treshold reached. ", my_id, count); 41 | pthread_cond_signal(&count_threshold_cv); 42 | printf("Just send signal.\n"); 43 | } 44 | printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", my_id, count); 45 | pthread_mutex_unlock(&count_mutex); 46 | 47 | /* Передача управления другим тредам */ 48 | sleep(1); 49 | } 50 | pthread_exit(NULL); 51 | } 52 | 53 | void *watch_count(void *t) { 54 | long my_id = (long)t; 55 | 56 | printf("Starting watch_count(): thread %ld\n", my_id); 57 | 58 | /* 59 | * Блокировка мьютекса и ожидание сигнала. Важно, что 60 | * pthread_cond_wait поток автоматически и атомарно разблокирует 61 | * мьютекс, пока он ждёт. Также важно, что если COUNT_LIMIT 62 | * достигается перед вызовом этого потока ожидающим тредом, 63 | * цикл будет пропущен для того, чтобы предотвратить вечное ожидание 64 | * в потоке pthread_cond_wait. 65 | */ 66 | pthread_mutex_lock(&count_mutex); 67 | while (count < COUNT_LIMIT) { 68 | printf("watch_count(): thread %ld Count= %d. Going into wait...\n", my_id, count); 69 | pthread_cond_wait(&count_threshold_cv, &count_mutex); 70 | printf("watch_count(): thread %ld Condition signal received. Count= %d\n", my_id, count); 71 | } 72 | printf("watch_count(): thread %ld Updating the value of count...\n", my_id); 73 | count += 125; 74 | printf("watch_count(): thread %ld count now = %d.\n", my_id, count); 75 | printf("watch_count(): thread %ld Unlocking mutex.\n", my_id); 76 | pthread_mutex_unlock(&count_mutex); 77 | pthread_exit(NULL); 78 | } 79 | 80 | int main(int argc, char *argv[]) { 81 | int i; 82 | long threads_ids[NUM_THREADS] = {1, 2, 3}; 83 | pthread_t threads[NUM_THREADS]; 84 | pthread_attr_t attr; 85 | 86 | /* Инициализация мьютекса и условной переменной */ 87 | pthread_mutex_init(&count_mutex, NULL); 88 | pthread_cond_init(&count_threshold_cv, NULL); 89 | 90 | pthread_attr_init(&attr); 91 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 92 | pthread_create(&threads[0], &attr, watch_count, (void *)threads_ids[0]); 93 | pthread_create(&threads[1], &attr, inc_count, (void *)threads_ids[1]); 94 | pthread_create(&threads[2], &attr, inc_count, (void *)threads_ids[2]); 95 | 96 | /* Ожидание завершения всех потоков */ 97 | for (i = 0; i < NUM_THREADS; ++i) { 98 | pthread_join(threads[i], NULL); 99 | } 100 | printf("Main(): Waited and joined with %d threads. Final value of count = %d. Done.\n", NUM_THREADS, count); 101 | 102 | /* Освобождение использованных объектов */ 103 | pthread_attr_destroy(&attr); 104 | pthread_mutex_destroy(&count_mutex); 105 | pthread_cond_destroy(&count_threshold_cv); 106 | pthread_exit(NULL); 107 | } 108 | -------------------------------------------------------------------------------- /examples/lecture2/019_trylock_mutex_without_deadlock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef struct { 7 | int balance; 8 | pthread_mutex_t balance_mutex; 9 | } bank_account; 10 | 11 | typedef struct { 12 | bank_account *from; 13 | bank_account *to; 14 | int amount; 15 | } deposit_thr_args; 16 | 17 | void create_bank_account(bank_account **ba, int initial_amount) { 18 | int result = 0; 19 | bank_account *nba = (bank_account *)malloc(sizeof(bank_account)); 20 | if (nba == NULL) { 21 | /* Handle error */ 22 | } 23 | 24 | nba->balance = initial_amount; 25 | result = pthread_mutex_init(&nba->balance_mutex, NULL); 26 | if (result) { 27 | /* Handle error */ 28 | } 29 | 30 | *ba = nba; 31 | } 32 | 33 | void *deposit(void *ptr) { 34 | int result = 0; 35 | deposit_thr_args *args = (deposit_thr_args *)ptr; 36 | for (;;) { 37 | printf("FROM: %p, BEFORE LOCKING %p\n", args->from, args->from); 38 | if ((result = pthread_mutex_lock(&(args->from->balance_mutex))) != 0) { 39 | /* Handle error */ 40 | } 41 | printf("FROM: %p, AFTER LOCKING %p\n", args->from, args->from); 42 | 43 | sleep(2); 44 | /* Not enough balance to transfer */ 45 | if (args->from->balance < args->amount) { 46 | printf("FROM: %p, BEFORE UNLOCKING %p\n", args->from, args->from); 47 | if ((result = pthread_mutex_unlock(&(args->from->balance_mutex))) != 0) { 48 | /* Handle error */ 49 | } 50 | printf("FROM: %p, AFTER UNLOCKING %p\n", args->from, args->from); 51 | return NULL; 52 | } 53 | 54 | printf("FROM: %p, BEFORE TRY LOCKING %p\n", args->from, args->to); 55 | if ((result = pthread_mutex_trylock(&(args->to->balance_mutex))) != 0) { 56 | printf("%p IS LOCKED. UNLOCKING %p\n", args->to, args->from); 57 | printf("FROM: %p, BEFORE UNLOCKING %p\n", args->from, args->from); 58 | if ((result = pthread_mutex_unlock(&(args->from->balance_mutex))) != 0) { 59 | /* Handle error */ 60 | } 61 | printf("FROM: %p, AFTER UNLOCKING %p\n", args->from, args->from); 62 | sleep(2); 63 | } 64 | else { 65 | printf("FROM: %p, AFTER TRY LOCKING %p\n", args->from, args->to); 66 | break; 67 | } 68 | } 69 | 70 | args->from->balance -= args->amount; 71 | args->to->balance += args->amount; 72 | 73 | printf("FROM: %p, BEFORE UNLOCKING %p\n", args->from, args->from); 74 | if ((result = pthread_mutex_unlock(&(args->from->balance_mutex))) != 0) { 75 | /* Handle error */ 76 | } 77 | printf("FROM: %p, AFTER UNLOCKING %p\n", args->from, args->from); 78 | printf("FROM: %p, BEFORE UNLOCKING %p\n", args->from, args->to); 79 | if ((result = pthread_mutex_unlock(&(args->to->balance_mutex))) != 0) { 80 | /* Handle error */ 81 | } 82 | printf("FROM: %p, AFTER UNLOCKING %p\n", args->from, args->to); 83 | 84 | free(ptr); 85 | return NULL; 86 | } 87 | 88 | int main(int argc, char *argv[]) { 89 | pthread_t thr1, thr2; 90 | int result = 0; 91 | 92 | bank_account *ba1 = NULL; 93 | bank_account *ba2 = NULL; 94 | create_bank_account(&ba1, 1000); 95 | create_bank_account(&ba2, 1000); 96 | 97 | deposit_thr_args *arg1 = (deposit_thr_args *)malloc(sizeof(deposit_thr_args)); 98 | if (arg1 == NULL) { 99 | /* Handle error */ 100 | } 101 | deposit_thr_args *arg2 = (deposit_thr_args *)malloc(sizeof(deposit_thr_args)); 102 | if (arg2 == NULL) { 103 | /* Handle error */ 104 | } 105 | 106 | arg1->from = ba1; 107 | arg1->to = ba2; 108 | arg1->amount = 100; 109 | 110 | arg2->from = ba2; 111 | arg2->to = ba1; 112 | arg2->amount = 100; 113 | 114 | /* Perform the deposits */ 115 | if ((result = pthread_create(&thr1, NULL, deposit, (void *)arg1)) != 0) { 116 | /* Handle error */ 117 | } 118 | if ((result = pthread_create(&thr2, NULL, deposit, (void *)arg2)) != 0) { 119 | /* Handle error */ 120 | } 121 | 122 | pthread_exit(NULL); 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /examples/lecture2/018_lock_mutex_without_deadlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Решение проблемы дедлока может быть решено следующим образом: 3 | * можно использовать предопределённый порядок в функции deposit(). 4 | * Тогда в таком случае каждый тред будет блокироваться на основе 5 | * идентификатора банковского счёта, определённого при инициализации 6 | * структуры. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | typedef struct { 15 | int balance; 16 | pthread_mutex_t balance_mutex; 17 | unsigned int id; /* Should never be changed after initialized */ 18 | } bank_account; 19 | 20 | typedef struct { 21 | bank_account *from; 22 | bank_account *to; 23 | int amount; 24 | } deposit_thr_args; 25 | 26 | unsigned int global_id = 1; 27 | 28 | void create_bank_account(bank_account **ba, int initial_amount) { 29 | int result = 0; 30 | bank_account *nba = (bank_account *)malloc(sizeof(bank_account)); 31 | if (nba == NULL) { 32 | /* Handle error */ 33 | } 34 | 35 | nba->balance = initial_amount; 36 | result = pthread_mutex_init(&nba->balance_mutex, NULL); 37 | if (result) { 38 | /* Handle error */ 39 | } 40 | 41 | nba->id = global_id++; 42 | *ba = nba; 43 | } 44 | 45 | void *deposit(void *ptr) { 46 | int result = 0; 47 | deposit_thr_args *args = (deposit_thr_args *)ptr; 48 | 49 | if (args->from->id == args->to->id) { 50 | return NULL; 51 | } 52 | 53 | /* Ensure proper ordering for locking */ 54 | if (args->from->id < args->to->id) { 55 | printf("FROM: %u, BEFORE LOCKING %u\n", args->from->id, args->from->id); 56 | if ((result = pthread_mutex_lock(&(args->from->balance_mutex))) != 0) { 57 | /* Handle error */ 58 | } 59 | printf("FROM: %u, AFTER LOCKING %u\n", args->from->id, args->from->id); 60 | sleep(2); 61 | printf("FROM: %u, BEFORE LOCKING %u\n", args->from->id, args->to->id); 62 | if ((result = pthread_mutex_lock(&(args->to->balance_mutex))) != 0) { 63 | /* Handle error */ 64 | } 65 | printf("FROM: %u, AFTER LOCKING %u\n", args->from->id, args->to->id); 66 | } 67 | else { 68 | printf("FROM: %u, BEFORE LOCKING %u\n", args->from->id, args->to->id); 69 | if ((result = pthread_mutex_lock(&(args->to->balance_mutex))) != 0) { 70 | /* Handle error */ 71 | } 72 | printf("FROM: %u, AFTER LOCKING %u\n", args->from->id, args->to->id); 73 | sleep(2); 74 | printf("FROM: %u, BEFORE LOCKING %u\n", args->from->id, args->from->id); 75 | if ((result = pthread_mutex_lock(&(args->from->balance_mutex))) != 0) { 76 | /* Handle error */ 77 | } 78 | printf("FROM: %u, AFTER LOCKING %u\n", args->from->id, args->from->id); 79 | } 80 | 81 | /* Not enough balance to transfer */ 82 | if (args->from->balance < args->amount) { 83 | printf("FROM: %u, BEFORE UNLOCKING %u\n", args->from->id, args->from->id); 84 | if ((result = pthread_mutex_unlock(&(args->from->balance_mutex))) != 0) { 85 | /* Handle error */ 86 | } 87 | printf("FROM: %u, AFTER UNLOCKING %u\n", args->from->id, args->from->id); 88 | printf("FROM: %u, BEFORE UNLOCKING %u\n", args->from->id, args->to->id); 89 | if ((result = pthread_mutex_unlock(&(args->to->balance_mutex))) != 0) { 90 | /* Handle error */ 91 | } 92 | printf("FROM: %u, AFTER UNLOCKING %u\n", args->from->id, args->to->id); 93 | return NULL; 94 | } 95 | 96 | args->from->balance -= args->amount; 97 | args->to->balance += args->amount; 98 | 99 | printf("FROM: %u, BEFORE UNLOCKING %u\n", args->from->id, args->from->id); 100 | if ((result = pthread_mutex_unlock(&(args->from->balance_mutex))) != 0) { 101 | /* Handle error */ 102 | } 103 | printf("FROM: %u, AFTER UNLOCKING %u\n", args->from->id, args->from->id); 104 | printf("FROM: %u, BEFORE UNLOCKING %u\n", args->from->id, args->to->id); 105 | if ((result = pthread_mutex_unlock(&(args->to->balance_mutex))) != 0) { 106 | /* Handle error */ 107 | } 108 | printf("FROM: %u, AFTER UNLOCKING %u\n", args->from->id, args->to->id); 109 | 110 | free(ptr); 111 | return NULL; 112 | } 113 | 114 | int main(int argc, char *argv[]) { 115 | pthread_t thr1, thr2; 116 | int result = 0; 117 | 118 | bank_account *ba1 = NULL; 119 | bank_account *ba2 = NULL; 120 | create_bank_account(&ba1, 1000); 121 | create_bank_account(&ba2, 1000); 122 | 123 | deposit_thr_args *arg1 = (deposit_thr_args *)malloc(sizeof(deposit_thr_args)); 124 | if (arg1 == NULL) { 125 | /* Handle error */ 126 | } 127 | deposit_thr_args *arg2 = (deposit_thr_args *)malloc(sizeof(deposit_thr_args)); 128 | if (arg2 == NULL) { 129 | /* Handle error */ 130 | } 131 | 132 | arg1->from = ba1; 133 | arg1->to = ba2; 134 | arg1->amount = 100; 135 | 136 | arg2->from = ba2; 137 | arg2->to = ba1; 138 | arg2->amount = 100; 139 | 140 | /* Perform the deposits */ 141 | if ((result = pthread_create(&thr1, NULL, deposit, (void *)arg1)) != 0) { 142 | /* Handle error */ 143 | } 144 | if ((result = pthread_create(&thr2, NULL, deposit, (void *)arg2)) != 0) { 145 | /* Handle error */ 146 | } 147 | 148 | pthread_exit(NULL); 149 | return 0; 150 | } 151 | -------------------------------------------------------------------------------- /examples/lecture3/002_namespaces.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace N1 { 4 | class A { 5 | public: 6 | void print() { 7 | std::cout << "N1::A" << std::endl; 8 | } 9 | 10 | static void static_print() { 11 | std::cout << "N1::A" << std::endl; 12 | } 13 | }; 14 | } 15 | 16 | namespace www { 17 | namespace example { 18 | namespace com { 19 | void print() { 20 | std::cout << "www::example::com::print()" << std::endl; 21 | } 22 | } 23 | } 24 | } 25 | 26 | namespace big { 27 | void foo1() { 28 | std::cout << "big::foo1()" << std::endl; 29 | } 30 | } 31 | 32 | namespace small { 33 | void foo() { 34 | std::cout << "small::foo()" << std::endl; 35 | } 36 | } 37 | 38 | namespace big { 39 | void foo2() { 40 | std::cout << "big::foo2()" << std::endl; 41 | } 42 | } 43 | 44 | struct A { 45 | static void print() { 46 | std::cout << "A::print()" << std::endl; 47 | } 48 | }; 49 | 50 | namespace global_from_namespace { 51 | struct A { 52 | static void print() { 53 | std::cout << "local::A::print()" << std::endl; 54 | } 55 | }; 56 | 57 | void print() { 58 | A::print(); 59 | ::A::print(); // global namespace 60 | } 61 | } 62 | 63 | void bar(int a) { 64 | std::cout << "::bar(int)" << std::endl; 65 | } 66 | 67 | namespace global_names_search { 68 | void foo(int a) { 69 | std::cout << "global_names_search::foo(int)" << std::endl; 70 | } 71 | 72 | void print() { 73 | foo(5); 74 | bar(5); 75 | } 76 | 77 | // after print => not found 78 | void bar(float a) { 79 | std::cout << "global_names_search::bar(float)" << std::endl; 80 | } 81 | 82 | namespace inner_names_search { 83 | void foo(float a) { 84 | std::cout << "global_names_search::inner_names_search::foo(float)" << std::endl; 85 | } 86 | 87 | void print() { 88 | foo(5); 89 | bar(5); 90 | } 91 | 92 | // after print => not found 93 | void bar(float a) { 94 | std::cout << "global_names_search::inner_names_search::bar(float)" << std::endl; 95 | } 96 | } 97 | } 98 | 99 | void foo(int a) { 100 | std::cout << "::foo(int)" << std::endl; 101 | } 102 | 103 | namespace using_example_outer { 104 | void foo(int a) { 105 | std::cout << "using_example_outer::foo(int)" << std::endl; 106 | } 107 | 108 | namespace using_example_inner { 109 | void before_print() { 110 | foo(5); 111 | } 112 | 113 | using ::foo; 114 | 115 | void after_print() { 116 | foo(5); 117 | } 118 | } 119 | } 120 | 121 | namespace using_namespace_example_outer { 122 | void before_print() { 123 | std::cout << "using_namespace_example_outer::before_print()" << std::endl; 124 | } 125 | namespace with_using { 126 | void before_print() { 127 | std::cout << "using_namespace_example_outer::with_using::before_print()" << std::endl; 128 | } 129 | 130 | namespace inner { 131 | void before_print() { 132 | std::cout << "using_namepace_example_outer::with_using::inner::before_print()" << std::endl; 133 | } 134 | } 135 | 136 | using namespace std; 137 | 138 | namespace inner { 139 | void after_print() { 140 | cout << "using_namepace_example_outer::with_using::inner::after_print()" << endl; 141 | } 142 | } 143 | 144 | void after_print() { 145 | cout << "using_namespace_example_outer::with_using::after_print()" << endl; 146 | } 147 | } 148 | void after_print() { 149 | std::cout << "using_namespace_example_outer::after_print()" << std::endl; 150 | } 151 | } 152 | 153 | namespace outer { 154 | namespace inner1 { 155 | void foo(int a) { 156 | std::cout << "outer::inner1::foo(int)" << std::endl; 157 | } 158 | } 159 | 160 | namespace inner2 { 161 | void foo(float a) { 162 | std::cout << "outer::inner2::foo(float)" << std::endl; 163 | } 164 | 165 | void print_with_using_namespace() { 166 | using namespace inner1; 167 | foo(42); 168 | } 169 | 170 | void print_with_using_foo() { 171 | using inner1::foo; 172 | foo(42); 173 | } 174 | 175 | void print_with_explicit_foo() { 176 | inner1::foo(42); 177 | inner2::foo(42); 178 | } 179 | } 180 | } 181 | 182 | namespace ADL { 183 | namespace outer { 184 | namespace inner { 185 | struct SumObject { 186 | SumObject() {} 187 | SumObject(int a, int b) : a(a), b(b) {} 188 | void print() { 189 | std::cout << a << " " << b << " " << std::endl; 190 | } 191 | int a; 192 | int b; 193 | }; 194 | 195 | SumObject operator+(SumObject const &a, SumObject const &b) { 196 | std::cout << "ADL::outer::inner::operator+" << std::endl; 197 | return SumObject(a.a + b.a, a.b + b.b); 198 | } 199 | } 200 | 201 | inner::SumObject operator-(inner::SumObject const &a, inner::SumObject const &b) { 202 | std::cout << "ADL::outer::operator-" << std::endl; 203 | return inner::SumObject(a.a - b.a, a.b - b.b); 204 | } 205 | } 206 | } 207 | 208 | // to make struct Anon as static member of this file 209 | namespace { 210 | struct NotStaticInAnonNamespace { 211 | static void foo() { 212 | std::cout << "NotStaticInAnonNamespace::foo()" << std::endl; 213 | } 214 | }; 215 | } 216 | 217 | namespace long_outer { 218 | namespace long_middle { 219 | namespace long_inner { 220 | void print() { 221 | std::cout << "long_outer::long_middle::long_inner::print()" << std::endl; 222 | } 223 | } 224 | } 225 | } 226 | 227 | int main(int argc, char *argv[]) { 228 | // simple namespace 229 | N1::A::static_print(); 230 | N1::A().print(); 231 | 232 | // nested namespaces 233 | www::example::com::print(); 234 | 235 | // namespace with divided implementation 236 | big::foo1(); 237 | big::foo2(); 238 | small::foo(); 239 | 240 | // accessing global namespace 241 | global_from_namespace::print(); 242 | 243 | // method names lookup 244 | global_names_search::print(); 245 | global_names_search::inner_names_search::print(); 246 | 247 | // using example 248 | using_example_outer::using_example_inner::before_print(); 249 | using_example_outer::using_example_inner::after_print(); 250 | 251 | // using namespace example 252 | using_namespace_example_outer::before_print(); 253 | using_namespace_example_outer::with_using::before_print(); 254 | using_namespace_example_outer::with_using::inner::before_print(); 255 | using_namespace_example_outer::with_using::inner::after_print(); 256 | using_namespace_example_outer::with_using::after_print(); 257 | using_namespace_example_outer::after_print(); 258 | 259 | // using from neighbor namespace 260 | outer::inner2::print_with_using_namespace(); 261 | outer::inner2::print_with_using_foo(); 262 | outer::inner2::print_with_explicit_foo(); 263 | 264 | // operator from namespace - Koenig's search (ADL, Argument-dependent name lookup) 265 | ADL::outer::inner::SumObject a(1, 2); 266 | a.print(); 267 | ADL::outer::inner::SumObject b(3, 4); 268 | b.print(); 269 | ADL::outer::inner::SumObject c; 270 | c.print(); 271 | c = a + b; 272 | c.print(); 273 | /*a = c - b; // operator- not found in global and in operands namespaces 274 | a.print();*/ 275 | c = ADL::outer::operator-(a, b); 276 | c.print(); 277 | ADL::outer::inner::SumObject d = operator+(a, b); 278 | d.print(); 279 | ADL::outer::inner::SumObject e = ADL::outer::inner::operator+(a, b); 280 | e.print(); 281 | 282 | // nameless namespaces 283 | NotStaticInAnonNamespace::foo(); 284 | 285 | // aliasing namespaces 286 | long_outer::long_middle::long_inner::print(); 287 | namespace short_alias = long_outer::long_middle::long_inner; 288 | short_alias::print(); 289 | 290 | { 291 | int k = 0; 292 | std::cout << "Scope defines new namespace. For example, k = " << k << std::endl; 293 | { 294 | int k = 42; 295 | std::cout << "Now we defined new k in inner scope => in inner namespace, so now k = " << k << std::endl; 296 | } 297 | std::cout << "Old k did not change: k = " << k << std::endl; 298 | { 299 | using std::cout; 300 | using std::endl; 301 | cout << "At least, prefer explicit namespace prefix or use aliases for long ones" << endl; 302 | } 303 | using namespace std; 304 | cout << "And don't use 'using namespace std' etc in header files!!!" << endl; 305 | } 306 | return 0; 307 | } 308 | -------------------------------------------------------------------------------- /drafts/build.md: -------------------------------------------------------------------------------- 1 | # Сборка проекта 2 | 3 | ## Системы сборки 4 | 5 | Часто IDE (такие как Visual Studio или Eclipse) имеют встроенные средства для 6 | сборки проекта. К сожалению пользоваться ими удобно далеко не во всех случаях. 7 | Как минимум: * при совместной работе над одним проектом каждому разработчику 8 | удобнее иметь собственные настройки IDE (к тому же, у разные участники проекта 9 | могут пользоваться разными IDE), при этом настройки сборки проекта должны всё же 10 | находиться в общем репозитории вместе с исходным кодом * при распространении 11 | программы в форме исходного кода не следует заставлять пользователя 12 | устанавливать на свой компьютер IDE, если для сборки проекта достаточно лишь 13 | компилятора и системы сборки * сборка и тестирование программы на сервере 14 | непрерывной интеграции должны происходить автоматически, т.е. запускаться из 15 | командной строки Поэтому даже если вы используете для разработки IDE, стоит всё 16 | же использовать для сборки проекта специально предназначенный для этого 17 | инструмент. Альтернативный вариант --- использовать для сборки проекта набор 18 | shell-скриптов (или batch-файлов Windows), но у такого подхода есть существенные 19 | недостатки: * в разных операционных системах используются разные оболочки, 20 | поэтому для каждой ОС придётся писать свой набор скриптов * процессе разработки 21 | целесообразно использовать инкрементальную сборку (т.е. пересобирать только 22 | изменившуюся часть проекта). Реализовать подобный режим в shell-скрипте будет 23 | нетривиально. Поэтому стоит всё же использовать для сборки проекта специально 24 | предназначенный для этого инструмент. Существует несколько подобных систем. Одна 25 | из самых популярных --- программа make и её варианты (например, GNU make, 26 | используемый по умолчанию в Linux). В дополнение к make существуют надстройки, 27 | такие как autoconf (входящий в состав 28 | [autotools](https://www.sourceware.org/autobook)), упрощающие портирование 29 | программ под различные платформы. Более современная и удобная альтернатива 30 | autoconf - программа [CMake](https://cmake.org), которую мы рассмотрим 31 | подробнее. На github имеется отличная подборка ссылок [Awesome 32 | CMake](https://github.com/onqtam/awesome-cmake), включающая в себя руководства, 33 | примеры скриптов и модули. 34 | 35 | ### Использование CMake 36 | 37 | Основная задача CMake --- это сборка проекта, но помимо этого CMake также удобно 38 | использовать для запуска тестов. Чтобы собрать проект с помощью CMake, 39 | необходимо описать шаги сборки в специально файле. 40 | 41 | По сути, такое описание --- это граф, вершинами которого являются исходные, 42 | промежуточные и результирующие файлы проекта (иногда множества файлов), а рёбра --- 43 | действия, которые необходимо предпринять, чтобы создать промежуточные и 44 | результирующие файлы. Сборка проекта представляет собой обход такого графа в 45 | топологическом порядке. Очень важным здесь является то, что сборка проекта 46 | описывается декларативно, а не императивно, т.е. описание не подразумевает 47 | какого-либо определённого порядка для не зависящих друг от друга шагов сборки. 48 | За счёт этого на многоядерной машине несколько шагов могут выполняться 49 | параллельно. 50 | 51 | CMake, используя описание, подготавливает сборку для той машины, на которой он 52 | был запущен: определяет установленный в системе компилятор, необходимые для него 53 | ключи командной строки, проверяет наличие необходимых библиотек и пути к ним и 54 | т.д. Результатом работы программы `cmake` является make-файл для используемой на 55 | данной платформе системы сборки (например, Makefile для GNU make в Linux, либо 56 | файл проекта Visual Studio в Windows; [полный 57 | список](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) 58 | поддерживаемых систем сборки представлен в документации). По сгенерированному 59 | файл осуществляется собственно сборка проекта. 60 | 61 | #### Файл проекта и основные команды 62 | 63 | По соглашению, основной файл проекта CMake называется `CMakeLists.txt`. Это файл 64 | содержит команды 65 | ([список](https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html) 66 | которых довольно обширен). Синтаксис команд довольно прост: вначале пишется имя 67 | команды, затем в скобках перечисляются её аргументы. Аргументы отделяются друг 68 | от друга пробелами. Перед значением аргумента может следовать его название. 69 | 70 | Рассмотрим некоторые команды. 71 | 72 | Команда [project](https://cmake.org/cmake/help/latest/command/project.html) 73 | задаёт название проекта, его версию и используемые языки программирование 74 | (исходя из списка языков CMake будет осуществлять поиск компиляторов). Пример: 75 | 76 | ``` 77 | project(my_project CXX) 78 | ``` 79 | 80 | (CXX здесь обозначает язык C++). Либо: 81 | 82 | ``` 83 | project(my_project VERSION 1.0.0 LANGUAGES CXX) 84 | ``` 85 | 86 | Команда 87 | [add_executable](https://cmake.org/cmake/help/latest/command/add_executable.html) 88 | добавляет к сборке исполняемый файл, компилируемый из заданного списка исходных 89 | файлов. Например: 90 | 91 | ``` 92 | add_executable(my_program main.cpp input.cpp output.cpp) 93 | ``` 94 | 95 | Похожим образом, но с помощью команды 96 | [add_library](https://cmake.org/cmake/help/latest/command/add_library.html) 97 | описывается сборка библиотеки: 98 | 99 | ``` 100 | add_library(my_shared_lib SHARED libsrc.cpp) 101 | ``` 102 | 103 | Библиотека `my_shared_lib` будет собрана как динамически загружаемая (shared 104 | object), это означает для запуска использующей библиотеку программы, библиотека 105 | должна быть установлена в системе. При этом один экземпляр библиотеки может 106 | использоваться несколькими разными программами. Альтернативным вариантом 107 | являются статические библиотеки. В процессе компоновки их код записывается 108 | непосредственно в исполняемый файл программы, поэтому установка библиотеки не 109 | требуется, но возможность использования одного экземпляра библиотеки несколькими 110 | разными программами теряется. Статические библиотеки описываются так: 111 | 112 | ``` 113 | add_library(my_static_lib STATIC libsrc.cpp) 114 | ``` 115 | 116 | Команда 117 | [target_link_libraries](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) 118 | позволяет скомпоновать исполняемый файл с библиотекой (либо две библиотеки между 119 | собой): 120 | 121 | ``` 122 | target_link_libraries(my_program my_static_lib) 123 | ``` 124 | 125 | Команда 126 | [include_directories](https://cmake.org/cmake/help/latest/command/include_directories.html) 127 | позволяет задать пути к заголовочным файлам. Пути задаются относительно 128 | директории с файлом `CMakeLists.txt`: 129 | 130 | ``` 131 | include_directories(src include) 132 | ``` 133 | 134 | Эта команда добавляет две директории, в которых будет осуществляться поиск 135 | заголовочных файлов: `./src` и `./include`. 136 | 137 | #### Возможности языка CMake 138 | 139 | Язык описания файлов проекта --- это полноценный язык программирования. К 140 | примеру, мы можете использовать переменные для хранения нужных вам значений: 141 | 142 | ``` 143 | set(SOURCES input.cpp output.cpp) 144 | add_executable(my_program main.cpp ${SOURCES}) 145 | ``` 146 | 147 | Значение переменной задаётся с помощью команды 148 | [set](https://cmake.org/cmake/help/latest/command/set.html), а считывается при 149 | помощи конструкции `${VARIABLE}` (`VARIABLE` - название переменной). 150 | 151 | При помощи команд [if](https://cmake.org/cmake/help/latest/command/if.html), 152 | `else`, `elseif` и `endif` осуществляется ветвление: 153 | 154 | ``` 155 | if (${CMAKE_HOST_WIN32}) 156 | add_executable(win_program main.cpp) 157 | endif() 158 | ``` 159 | 160 | В этом примере программа `win_program` будет компилироваться только если сборка 161 | запущена из операционной системы Windows. `CMAKE_HOST_WIN32` --- это встроенная 162 | переменная CMake. Имеется и множество других [встроенных 163 | переменных](https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html), 164 | описывающих систему, на которой выполняется сборка, а также влияющих на сам 165 | процесс сборки. 166 | 167 | В языке CMake имеются и другие привычные синтаксические конструкции: 168 | математический операции, циклы, функции. Команды CMake позволяют работать со 169 | строками, списками, с файловой системой и другими объектами. Подробно они 170 | описаны в [документации по 171 | командам](https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html). 172 | 173 | #### Запуск CMake 174 | 175 | CMake запускается из директории, в которой будет происходить сборка, т.е. в ней 176 | в итоге окажутся результат сборки и промежуточные файли. Она может совпадать с 177 | директорией проекта, но удобнее всё же собирать проект в отдельной директории. 178 | Это позволит легко удалить все промежуточные файли, если вам захочется собрать 179 | проект "с нуля", а также избавит от необходимости настраивать исключения для 180 | системы контроля версий (`.gitignore`). 181 | 182 | Итак, допустим, мы создали внутри директории проекта поддиректории `build` и 183 | `build/debug`: 184 | 185 | ``` 186 | mkdir -p build/debug 187 | ``` 188 | 189 | Для выполнения сборки следует перейти в эту директорию и запустить CMake: 190 | 191 | ``` 192 | cd build/debug 193 | cmake ../.. -DCMAKE_BUILD_TYPE=Debug 194 | ``` 195 | 196 | В качестве первого аргумента указывается путь к исходному коду (т.е. директории 197 | с файлом `CMakeLists.txt`). Далее, мы с помощью ключа `-D` определили значение 198 | переменной `CMAKE_BUILD_TYPE` как `Debug`. Это означает, что проект будет 199 | собираться в конфигурации для отладки (по умолчанию это означает: включить 200 | генерацию отладочной информации и отключать оптимизацию). 201 | 202 | Затем из этой же директории запускаем make: 203 | 204 | ``` 205 | make -j8 206 | ``` 207 | 208 | В качестве параметра `-j` указывается количество параллельных потоков сборки. 209 | Как правило, следует указать количество ядер процессора (с учётом 210 | hyperthreading). В скриптах для сборки часто используют команду `nproc`, с 211 | помощью которой можно определить количество ядер: 212 | 213 | ``` 214 | make -j$(nproc) 215 | ``` 216 | 217 | Аналогичным образом собирается проект в конфигурации `Release`. Конфигурация по 218 | умолчанию не очень полезна, т.к. в ней отключена как отладочная информация, так 219 | и оптимизация. 220 | -------------------------------------------------------------------------------- /examples/c_homework/team_projects.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MIN_TEAM_SIZE 3 7 | #define MAX_TEAM_SIZE 4 8 | 9 | enum track_id {_ML = 1, _WEB}; 10 | enum group_id {_11 = 1, _12, _13}; 11 | 12 | struct student { 13 | char *name; 14 | char *surname; 15 | enum track_id track; 16 | enum group_id group; 17 | char *link_to_git_profile; 18 | }; 19 | 20 | struct team { 21 | char *name; 22 | struct { 23 | char *name; 24 | char *description; 25 | } project; 26 | size_t size; 27 | struct student *members; 28 | char *lead; 29 | }; 30 | 31 | char input_char(); 32 | 33 | /* Returns NULL on failure */ 34 | char *input_string(); 35 | 36 | /* Returns 0 on failure */ 37 | int input_int(); 38 | 39 | /* Creates new team. Returns false on failure */ 40 | bool create(struct team **new_team_p); 41 | 42 | bool is_space(char c); 43 | 44 | /* Returns new allocated string or NULL on error */ 45 | char *get_trimmed_string(char const * const str); 46 | 47 | /* Add backslashes before pattern characters in second parameter and print in quotes */ 48 | void print_escaped_string(const char * const str, const char symbols_to_escape[]); 49 | 50 | /* Does not allocate new memory. Only returns pointer to substring in original string */ 51 | char *get_url_substring_without_schema(char * str); 52 | 53 | /* Prints trimmed and espaced quoted string */ 54 | void print_formatted_string(const char * const string, const char symbols_to_escape[]); 55 | 56 | /* Prints struct in JSON format */ 57 | void print_team_as_json(const struct team * const team); 58 | 59 | void delete(struct team *team); 60 | 61 | int main() { 62 | struct team *new_team = NULL; 63 | bool success = create(&new_team); 64 | if (success) { 65 | print_team_as_json(new_team); 66 | } 67 | delete(new_team); 68 | return 0; 69 | } 70 | 71 | char input_char() { 72 | char c = '\0'; 73 | int result = 0; 74 | do { 75 | result = scanf("%c", &c); 76 | } while (result != 1); 77 | return c; 78 | } 79 | 80 | char *input_string() { 81 | struct buffer { 82 | char *string; 83 | size_t size; 84 | size_t capacity; 85 | } buf = {NULL, 0, 0}; 86 | char c = '\0'; 87 | while (c = input_char(), c != EOF && c != '\n') { 88 | if (buf.size + 1 >= buf.capacity) { 89 | size_t new_capacity = !buf.capacity ? 1 : buf.capacity * 2; 90 | char *tmp = (char *)malloc((new_capacity + 1) * sizeof(char)); 91 | if (!tmp) { 92 | if (buf.string) { 93 | free(buf.string); 94 | } 95 | return NULL; 96 | } 97 | if (buf.string) { 98 | tmp = strcpy(tmp, buf.string); 99 | free(buf.string); 100 | } 101 | buf.string = tmp; 102 | buf.capacity = new_capacity; 103 | } 104 | buf.string[buf.size] = c; 105 | buf.string[buf.size + 1] = '\0'; 106 | ++buf.size; 107 | } 108 | return buf.string; 109 | } 110 | 111 | int input_int() { 112 | char c = '\0'; 113 | int result = 0; 114 | while (c = input_char(), c != EOF && c != '\n') { 115 | if (!(c >= '0' && c <= '9')) { 116 | char *buf = input_string(); /* Read to the end of the string */ 117 | if (buf) { 118 | free(buf); 119 | } 120 | return 0; 121 | } 122 | result = result * 10 + c - '0'; 123 | } 124 | return result; 125 | } 126 | 127 | bool create(struct team **new_team_p) { 128 | if (!new_team_p) { 129 | return false; 130 | } 131 | *new_team_p = (struct team *)malloc(sizeof(struct team)); 132 | struct team *new_team = *new_team_p; 133 | if (!new_team) { 134 | return false; 135 | } 136 | new_team->name = NULL; 137 | new_team->name = NULL; 138 | new_team->project.name = NULL; 139 | new_team->project.description = NULL; 140 | new_team->size = 0; 141 | new_team->members = NULL; 142 | char *string = NULL; 143 | printf("Введите название команды\n"); 144 | string = input_string(); 145 | if (!string) { 146 | return false; 147 | } 148 | new_team->name = string; 149 | printf("Введите название проекта:\n"); 150 | string = input_string(); 151 | if (!string) { 152 | return false; 153 | } 154 | new_team->project.name = string; 155 | printf("Введите описание проекта:\n"); 156 | string = input_string(); 157 | if (!string) { 158 | return false; 159 | } 160 | new_team->project.description = string; 161 | int size = 0; 162 | do { 163 | printf("Введите размер команды (мин: %d - макс: %d):\n", MIN_TEAM_SIZE, MAX_TEAM_SIZE); 164 | size = input_int(); 165 | } while (!(size >= MIN_TEAM_SIZE && size <= MAX_TEAM_SIZE)); 166 | new_team->size = (size_t)size; 167 | new_team->members = (struct student *)malloc(new_team->size * sizeof(struct student)); 168 | if (!new_team->members) { 169 | return false; 170 | } 171 | for (size_t i = 0; i < new_team->size; ++i) { 172 | new_team->members[i] = (struct student){}; 173 | printf("Введите имя члена команды № %ld\n", i + 1); 174 | string = input_string(); 175 | if (!string) { 176 | return false; 177 | } 178 | new_team->members[i].name = string; 179 | printf("Введите фамилию члена команды № %ld\n", i + 1); 180 | string = input_string(); 181 | if (!string) { 182 | return false; 183 | } 184 | new_team->members[i].surname = string; 185 | 186 | int track = 0; 187 | do { 188 | printf("Введите номер трека: ML - %d, WEB - %d\n", _ML, _WEB); 189 | track = input_int(); 190 | } while (!(track == _ML || track == _WEB)); 191 | new_team->members[i].track = track; 192 | 193 | int group = 0; 194 | do { 195 | printf("Введите номер группы члена команды № %ld (%d - %d):\n", i + 1, _11, _13); 196 | group = input_int(); 197 | } while (!(group >= _11 && group <= _13)); 198 | new_team->members[i].group = (size_t)group; 199 | printf("Введите ссылку на профиль в git-репозитории члена команды № %ld:\n", i + 1); 200 | string = input_string(); 201 | if (!string) { 202 | return false; 203 | } 204 | new_team->members[i].link_to_git_profile = string; 205 | } 206 | int team_lead_idx = 0; 207 | do { 208 | printf("Введите номер члена команды, который будет выполнять роль лидера: (1..%d)\n", size); 209 | team_lead_idx = input_int(); 210 | } while (!(team_lead_idx >= 1 && team_lead_idx <= size)); 211 | struct student team_lead_member = new_team->members[team_lead_idx - 1]; 212 | new_team->lead = (char *)malloc(strlen(team_lead_member.name) + strlen(team_lead_member.surname) + 2); 213 | if (!new_team->lead) { 214 | return false; 215 | } 216 | strcpy(new_team->lead, team_lead_member.name); 217 | strcat(new_team->lead, " "); 218 | strcat(new_team->lead, team_lead_member.surname); 219 | return true; 220 | } 221 | 222 | bool is_space(char c) { 223 | return c == ' ' || c == '\t'; 224 | } 225 | 226 | char *get_trimmed_string(char const * const str) { 227 | if (!str) { 228 | return NULL; 229 | } 230 | char *tmp = (char *)malloc((strlen(str) + 1) * sizeof(char)); 231 | if (!tmp) { 232 | return NULL; 233 | } 234 | tmp[0] = '\0'; 235 | size_t i = 0; 236 | size_t j = 0; 237 | while (is_space(str[j])) { 238 | ++j; 239 | } 240 | while (str[j] != '\0') { 241 | while (str[j] != '\0' && !is_space(str[j])) { 242 | tmp[i++] = str[j++]; 243 | } 244 | size_t first_space_index = j; 245 | while (is_space(str[j])) { 246 | ++j; 247 | } 248 | if (str[j] != '\0') { 249 | tmp[i] = '\0'; 250 | tmp = strncat(tmp, str + first_space_index, j - first_space_index + 1); 251 | i += j - first_space_index + 1; 252 | ++j; 253 | } 254 | } 255 | tmp[i] = '\0'; 256 | char *result = malloc((strlen(tmp) + 1) * sizeof(char)); 257 | if (!result) { 258 | free(tmp); 259 | return NULL; 260 | } 261 | result = strcpy(result, tmp); 262 | free(tmp); 263 | return result; 264 | } 265 | 266 | void print_escaped_string(const char * const str, const char symbols_to_escape[]) { 267 | size_t i = 0; 268 | printf("\""); 269 | while (str[i] != '\0') { 270 | if (strchr(symbols_to_escape, str[i])) { 271 | printf("\\"); 272 | } 273 | printf("%c", str[i]); 274 | ++i; 275 | } 276 | printf("\""); 277 | } 278 | 279 | char *get_url_substring_without_schema(char * str) { 280 | const char *pattern = "://"; 281 | char *result = str; 282 | result = strstr(str, pattern); 283 | if (!result) { 284 | return str; 285 | } 286 | result += strlen(pattern); 287 | return result; 288 | } 289 | 290 | void print_formatted_string(const char * const string, const char symbols_to_escape[]) { 291 | char *trimmed_string = NULL; 292 | trimmed_string = get_trimmed_string(string); 293 | print_escaped_string(trimmed_string ? trimmed_string : string, symbols_to_escape); 294 | if (trimmed_string) { 295 | free(trimmed_string); 296 | trimmed_string = NULL; 297 | } 298 | } 299 | 300 | void print_team_as_json(const struct team * const team) { 301 | const char symbols_to_escape[] = "\\\""; 302 | printf("{\t\n"); 303 | printf("\t\"name\": "); 304 | print_formatted_string(team->name, symbols_to_escape); 305 | printf(",\n"); 306 | printf("\t\"project\": {\n"); 307 | printf("\t\t\"name\": "); 308 | print_formatted_string(team->project.name, symbols_to_escape); 309 | printf(",\n"); 310 | printf("\t\t\"description\": "); 311 | print_formatted_string(team->project.description, symbols_to_escape); 312 | printf("\n"); 313 | printf("\t},\n"); 314 | printf("\t\"size\": %ld,\n", team->size); 315 | printf("\t\"members\": [\n"); 316 | for (size_t i = 0; i < team->size; ++i) { 317 | printf("\t\t{\n"); 318 | printf("\t\t\t\"name\": "); 319 | print_formatted_string(team->members[i].name, symbols_to_escape); 320 | printf(",\n"); 321 | printf("\t\t\t\"surname\": "); 322 | print_formatted_string(team->members[i].surname, symbols_to_escape); 323 | printf(",\n"); 324 | printf("\t\t\t\"group\": \"%s-1%d\",\n", team->members[i].track == _ML ? "ML" : "WEB", team->members[i].group); 325 | printf("\t\t\t\"link_to_git_profile\": "); 326 | /* A little hack - technopark portal transforms links with schema in html tags */ 327 | char *url_without_schema = get_url_substring_without_schema(team->members[i].link_to_git_profile); 328 | print_formatted_string(url_without_schema, symbols_to_escape); 329 | printf("\n"); 330 | printf("\t\t}%c\n", i + 1 != team->size ? ',' : ' '); 331 | } 332 | printf("\t],\n"); 333 | printf("\t\"team_lead\": "); 334 | print_formatted_string(team->lead, symbols_to_escape); 335 | printf("\n}\n"); 336 | } 337 | 338 | void delete(struct team *team) { 339 | if (!team) { 340 | return; 341 | } 342 | if (team->name) { 343 | free(team->name); 344 | } 345 | if (team->project.name) { 346 | free(team->project.name); 347 | } 348 | if (team->project.description) { 349 | free(team->project.description); 350 | } 351 | for (size_t i = 0; i < team->size; ++i) { 352 | if (team->members[i].name) { 353 | free(team->members[i].name); 354 | } 355 | if (team->members[i].surname) { 356 | free(team->members[i].surname); 357 | } 358 | if (team->members[i].link_to_git_profile) { 359 | free(team->members[i].link_to_git_profile); 360 | } 361 | } 362 | if (team->members) { 363 | free(team->members); 364 | } 365 | if (team->lead) { 366 | free(team->lead); 367 | } 368 | free(team); 369 | } 370 | 371 | -------------------------------------------------------------------------------- /compiler.md: -------------------------------------------------------------------------------- 1 | # Работа с компилятором 2 | 3 | 4 | 5 | Компилятор GCC предоставляет множество опций командной строки. Полезно будет 6 | ознакомиться с основными из них. Список всех опций и их описание можно прочитать 7 | на [сайте GCC](https://gcc.gnu.org/onlinedocs/). 8 | 9 | 10 | 11 | Заметим что Clang во многом совместим с GCC и описанные здесь основные опции 12 | работают и с Clang (если явно не сказано обратное). У Clang также имеется 13 | подробная [документация](http://clang.llvm.org/docs/UsersManual.html). 14 |   15 | 16 |   17 | 18 |   19 | 20 | ## Функции драйвера компилятора 21 | 22 | Программа `gcc` (а также `g++`) --- это так называемый драйвер компилятора, т.е. 23 | обёртка, служащая для запуска других программ --- компилятора в узком смысле 24 | (программы, "переводящей" другие программы с языка высокого уровня на язык 25 | ассемблера), ассемблера и компоновщика. По умолчанию `g++` запускает все три 26 | программы (компилятор, ассемблер и компоновщик) последовательно. Таким образом, 27 | исполнение 28 | 29 | g++ test.cpp 30 | 31 | создаст сразу исполняемый файл с программой, исходный текст которой взят из 32 | файла `test.cpp`. Имя выходного файла по умолчанию --- `a.out`. Для того чтобы 33 | задать произвольное имя выходного файла используется ключ `-o`: 34 | 35 | g++ test.cpp -o test 36 | 37 | Порядок ключей и имён файлов в большинстве случаев произвольный, т.е. ту же 38 | самую команду можно записать как 39 | 40 | g++ -o test test.cpp 41 | 42 | Для того чтобы получить файл с объектным кодом (т.е. пропустить программу 43 | последовательно через компилятор и ассемблер) служит ключ `-c`: 44 | 45 | g++ -c test.cpp -o test.o 46 | 47 | Если же требуется получить файл на языке ассемблера, следует использовать ключ 48 | `-S`: 49 | 50 | g++ -S test.cpp -o test.s 51 | 52 | Скомпоновать несколько объектных файлов в один исполняемый можно следующим 53 | образом: 54 | 55 | g++ file1.o file2.o -o myprogram 56 | 57 | При компоновке важно использовать правильный драйвер: `g++` для программ, 58 | написанных на языке C++ и `gcc` для программ на языке C. От выбора драйвера 59 | зависит набор стандартных библиотек, который будет по умолчанию подключен к 60 | программе. 61 | 62 | 63 | 64 | В операционной системе OS X за файлами `gcc` и `g++` скрывается компилятор 65 | Clang, существенная часть которого разработана самой компанией Apple. До того 66 | как Clang был создан, в OS X использовался GCC. Чтобы не ломать сборку 67 | проектов, в которых явно указано имя файла `gcc` или `g++`, инженеры Apple 68 | решили оставить файлы с такими именами. 69 | 70 | ## Выбор языка и стандарта 71 | 72 | Язык программы (C либо C++) определяется драйвером исходя из расширения файла и 73 | не зависит от того, какой драйвер (`gcc` или `g++` используется для компиляции). 74 | При необходимости язык можно задать явно (с помощью опции `-x`), но лучше, 75 | разумеется, пользоваться общепринятыми расширениями файлов: `.c` для программ 76 | на языке C и `.cpp` (или `.cc`) для языка C++. 77 | 78 | Компилятор GCC поддерживает несколько стандартов языков C и C++ различающихся 79 | набором доступных возможностей языка. Версия стандарта задаётся при помощи ключа 80 | `-std=`, например: 81 | 82 | g++ -c test.cpp -std=c++14 83 | 84 | задаёт стандарт C++14. GCC поддерживает некоторые расширения языков C и C++ (их 85 | [список](https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html) весьма 86 | внушительный). Чтобы разрешить их использование, используются обозначение 87 | стандарта в котором `c` заменяется на `gnu` (а `c++` на `gnu++`). Например: 88 | 89 | gcc -c test.c -std=gnu11 90 | 91 | запускает компиляцию с использованием стандарта C11 с включенными расширениями. 92 | 93 | ## Пути к заголовочным файлам и макроопределния 94 | 95 | Если вы используете в программе директиву препроцессора вида 96 | `#include `, компилятор должен каким-то образом найти в файловой 97 | системе заголовочный файл `header.hpp`. По умолчанию, GCC ищет файлы в 98 | системных путях, заданных ещё в процессе сборки самого компилятора, таких как 99 | `/usr/include`. Часто требуется добавить к ним дополнительные пути к исползуемым 100 | библиотекам. Для этого служит опция командной строки `-I`. Например: 101 | 102 | g++ -c file.cpp -Ithird-party/include -Iinclude 103 | 104 | добавляет к списку путей директории `third-party/include` и `include` (которые 105 | должны находиться в текущей директории). 106 | 107 | Напомним, что при использовании директивы `#include` с кавычками, т.е. 108 | `#include "header.hpp"` для поиска также используется директория, в которой 109 | находится компилируемый файл. 110 | 111 | В некоторых случаях поведением программы удобно урпавлять с помощью макросов. 112 | Например, библиотека glibc определяет макрос `assert`, поведение которого 113 | изменяется в зависимости от того, определён ли макрос `NDEBUG`. А именно, если 114 | `NDEBUG` определён, то `assert` никак не влияет на поведение программы. Если 115 | же он не определён, то `assert` проверяет, истинно ли значение, переданное ему 116 | в качестве аргумента, и если оно ложно, программа аварийно завершается. Такое 117 | поведение полезно при отладке, но в дистрибутиве программы, передаваемой 118 | пользователю, лишние проверки нежелательны, т.к. отрицательно сказываются на 119 | производительности программы. Поэтому при компиляции выпускаемой версии 120 | программы определяют макрос NDEBUG: 121 | 122 | g++ -c program.cpp -DNDEBUG 123 | 124 | Опция `-D` опредяет макрос `NDEBUG` так, как если бы в первой строке программы 125 | была директива 126 | 127 | ```C++ 128 | #define NDEBUG 129 | ``` 130 | 131 | С помощью опции `-D` можно также задать значение определяемого макроса: 132 | 133 | g++ -c program.cpp -DVERSION="1.1" 134 | 135 | эквивалентно добавлению строки 136 | 137 | ```C++ 138 | #define VERSION "1.1" 139 | ``` 140 | 141 | в начало компилируемого файла. 142 | 143 | ## Опции, влияющие на программы с неопределённым поведением 144 | 145 | Отличительной чертой языков С и C++ является т.н. "неопределённое поведение": 146 | стандарты этих языков подразумевают, что программист позаботится о том, чтобы в 147 | программе отсутствовали некоторые виды поведения, например, обращение к 148 | неинициализированным переменным. Компилятор, в свою очередь, может полагаться на 149 | это, поскольку стандарт не предъявляет к компилятору никаких требований 150 | относительно того, какой именно код должен сгенерировать компилятор при наличии 151 | в программе неопределённого поведения. Такое соглашение между авторами 152 | стандарта, авторами компилятора и программистами позволяет во многих случаях 153 | генерировать код с максимальным быстродействием. В то же время, обеспечить 154 | отсутствие в программе некоторых видов неопределённого поведения трудно, а 155 | задача проверки кода на отстуствие неопределённого поведения алгоритмически 156 | неразрешима. Поэтому авторы компилятора GCC добавили несколько опций, которые 157 | позволяют "доопределить" стандарты языков C и C++, придав некоторым случаям 158 | неопределённого поведения вполне конкретную семантику. 159 | 160 | В частности, опция `-fwrapv` (от "wrap oVerflow") определяет, что арифметические 161 | операции над целыми числами со знаком должны выполняться с циклическим 162 | переполнением. К примеру, согласно стандарту C++, в следующем примере 163 | 164 | ```C++ 165 | int x; 166 | // ... 167 | if (x + 1 > x) { 168 | // ... 169 | } 170 | ``` 171 | 172 | переполнение при вычислении `x + 1` является неопределённым поведением, поэтому 173 | компилятор может предположить, что этого никогда не произойдёт, а условие `x + 1 > 174 | x` всегда истинно и удалить код, отвечающий за проверку этого условия. Однако, 175 | если задать опцию `-fwrapv` компилятор будет основываться на том, что 176 | переполнение циклическое, поэтому `x + 1` может быть отрицательным (например, 177 | при 32-битном `int`, `0x7FFFFFFF + 1` равно `0x80000000` или `-2147483648`) и не 178 | будет удалять проверку. 179 | 180 | Ещё одно проблематичное для многих правила языков C и C++ --- это правило о 181 | строгом соответствии псевдонимов (strict aliasing) и связанная с ним оптимизация --- 182 | анализ псевдонимов, основанный на типах (type based alias analysis). Согласно 183 | стандартам языков C и C++, через указатель на тип `T` допускается получать 184 | доступ только к значениям типа `T`. Исключение составляют указатели на 185 | символьный тип (`char`, `signed char` и `unsigned char`), т.к. через них можно 186 | считывать значения других типов. Например, следующий код не вызывает 187 | неопределённого поведения: 188 | 189 | ```C++ 190 | int x = 5; 191 | const char* p = (char *)&x; 192 | return *p; 193 | ``` 194 | 195 | а вот этот пример --- вызывает: 196 | 197 | ```C++ 198 | double x = 1.0; 199 | return *(int *)(&x); 200 | ``` 201 | 202 | За счёт данного правила компилятор может в следующем фрагменте кода 203 | 204 | ```C++ 205 | int foo(int* x, double* y) 206 | { 207 | y[0] = x[0]; 208 | return x[0]; 209 | } 210 | ``` 211 | 212 | считать, что присваивание `y[0] = x[0]` не меняет значения `x[0]` (поскольку 213 | указатели `x` и `y` различаются) и выполнить одну операцию чтения из памяти 214 | вместо двух. 215 | 216 | Ключ `-fno-strict-aliasing` отключает данный вид анализа, т.е. заставляет 217 | компилятор предполагать, что любые два указателя могут быть псевдонимами друг 218 | друга, если обратное не следует, например, из правил адресной арифметики. 219 | 220 | ### Предупреждения 221 | 222 | Предупреждения компилятора сообщают программисту о найденных в программе 223 | потенциальных проблемах --- конструкциях, хотя и разрешённых стандартом языка, 224 | но могут свидетельствовать о наличии в программе ошибки. 225 | 226 | Рассмотрим такой пример: 227 | 228 | ```C++ 229 | if (x = 0) { 230 | std::cout << "x is zero!"; 231 | } 232 | ``` 233 | 234 | Ошибка здесь заключается в том, что вместо оператора сравнения `==` был 235 | использован оператор присваивания `=`. Условие в `if` всегда ложно и поэтому 236 | строка "x is zero!" никогда не будет выведена. Несмотря на явную ошибку, этот 237 | код абсолютно корректен с точки зрения стандарта C++. Если мы попробуем 238 | скомпилировать его с включенными предупреждениями 239 | 240 | g++ -с -Wall test.cpp 241 | 242 | то получим сообщение от компилятора: 243 | 244 | test.cc: In function ‘int main()’: 245 | test.cc:6:11: warning: suggest parentheses around assignment used as truth value [-Wparentheses] 246 | if (x = 0) { 247 | ^ 248 | 249 | GCC сообщает нам, что если мы действительно не имели в виду сравнение, а хотим 250 | использовать результат присваивания в качестве булева значения, то следует 251 | заключить его в скобки. 252 | 253 | Большинство предупреждений имеют отдельный ключ командандной строки, который 254 | отвечает только за данное предупреждение. Также существуют ключи, активирующие 255 | сразу целую группу предупреждений. 256 | 257 | Так, предупреждения, которые с высокой вероятностью вызваны ошибкой в программе 258 | активируются опцией `-Wall`. Предупреждения, активируемые опцией `-Wextra`, 259 | могут в некоторых случаях вызывать ложно-положительные срабатывания, но в 260 | большинстве случаях также полезны. Рекомендуется использовать как `-Wall`, так и 261 | `-Wextra` в своих проектах. 262 | 263 | Наконец, 264 | [предупреждения](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options), 265 | не включенные ни в одну из этих групп, могут быть полезны в зависимости от 266 | стандартов кодирования, применямых в конкретном проекте. Например, разработчики 267 | проекта могут договориться о том, чтобы всегда помечать перекрываемые 268 | виртуальные методы с помощью ключевого слова `override`. В этом случае полезно 269 | будет задействовать опцию `-Wsuggest-override` (данная опция присутствует только 270 | в GCC начиная с версии 5), чтобы компилятор выдывал предупреждение о виртуальных 271 | методах, в объявлении которых ключевое слово `override` отсутствует. 272 | 273 | ### Оптимизации компилятора 274 | 275 | Оптимизатор присутствует в большинстве современных компиляторов С и C++, таких 276 | как GCC, Clang и MSVC. Функция оптимизатора заключается в том, чтобы 277 | преобразовать исходную программу в эквивалентную ей семантически, но работающую 278 | быстрее. Оптимизатор GCC организован в виде конвеера, состоящего из т.н. 279 | проходов. Каждый проход выполняет некоторый вид преобразований программы, 280 | хранящейся в памяти в виде промежуточного представления. Это представление 281 | последовательно подаётся на вход каждого из проходов (этапов конвеера). Как и 282 | предпреждения, оптимизации объединены в группы, активируемые различными ключами 283 | командной строки. Так, ключ `-O1` (либо `-O`) включает наиболее простые и быстро 284 | выполняемые оптимизации, `-O2` выполняет также и более "дорогие" оптимизации. 285 | Наконец, в `-O3` входят сложные оптимизации, порой имеющие квадратичное (по 286 | количеству кода в отдельной функции программы) время работы. Ключ `-Os` 287 | настраивает оптимизатор так, чтобы генерировать код меньшего размера (иногда в 288 | ущерб быстродействию). Такой режим полезен при компиляции программ, 289 | предназначенных для встраиваемых систем (например, микроконтроллеров). 290 | 291 | Чтобы получить общее представление о том, как работает оптимизатор, рассмотрим в 292 | качестве примера один из проходов оптимизатора --- встраивание функций 293 | (inlining). Встраивание выполняет подстановку тела функции в место её вызова. 294 | Например, такой код: 295 | 296 | ```C++ 297 | int add2(int x) 298 | { 299 | return x + x; 300 | } 301 | 302 | int add3(int x) 303 | { 304 | return x + add2(x); 305 | } 306 | ``` 307 | 308 | Можно преобразовать в эквивалентный: 309 | 310 | ```C++ 311 | int add2(int x) 312 | { 313 | return x + x; 314 | } 315 | 316 | int add3(int x) 317 | { 318 | return x + x + x; 319 | } 320 | ``` 321 | 322 | тем самым сэкономив в функции `add3` время на копировании аргументов функции 323 | `add2`, её вызове и возврате из функции. Повторимся: оптимизатор работает с 324 | промежуточным представлением программы, а не с исходным кодом, поэтому данный 325 | пример, разумеется, условный. Кроме того, встраивание на самом деле пытается 326 | скопировать код функции без изменений, т.е. результат будет больше похож на 327 | 328 | ```C++ 329 | int add3(int x) 330 | { 331 | int __add2_x = x; 332 | int __add2_result = __add2_x + __add2_x; 333 | return x + __add2_result; 334 | } 335 | ``` 336 | 337 | От лишних операций копирования помогут избавиться последующие этапы конвеера: 338 | проход распространения констант и копий (constant and copy propagation), а также 339 | проход устранения мёртвого кода (dead code elimination). Как видно из этого 340 | примера, выполнение одной оптимизации может предоставить возможность выполнить 341 | другие, поэтому конвеер оптимизатор устроен достаточно сложно: некоторые проходы 342 | выполняются несколько раз, а их порядок тщательно выверен. 343 | 344 | Оптимизация позволяет значительно увеличить производительность программы: 345 | зачастую оптимизированный код выполняется в 1,5-3 раза быстрее 346 | неоптимизированного. Разумеется оптимизации не бесплатны: компиляция программы с 347 | включённой оптимизацией выполняется медленнее. Ещё один недостаток 348 | оптимизированного кода --- меньшее удобство в отладке (например, в отладчике 349 | может быть недоступен просмотр значений некоторых переменных). Частично этот 350 | недостаток устраняется опцией `-Og` (доступна только в GCC): она выключает те 351 | проходы оптимизатора, которые отрицательно сказываются на качестве отладочной 352 | информации. Производительность кода с этой опцией примерно соответствует 353 | производительности `-O1`. 354 | 355 | ### Отладочная информация 356 | 357 | Отладочная информация содержит соответствия между элементами бинарного кода 358 | (адреса, регистры процессора) и исходного кода (номера строк, имена функций и 359 | переменных) программы. Запись отладочной информации в генерируемые компилятором 360 | файлы включается с помощью ключа `-g`. Ключ `-ggdb3` включает вывод 361 | дополнительной информаций, специфичной для отладчика GDB. Подробнее об отладке 362 | (и отладочной информации) можно прочитать в статье [Отладка программ с помощью 363 | GDB](gdb-intro.md). 364 | --------------------------------------------------------------------------------