Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 23, средняя оценка - 4.65
HighPredator
5541 / 1854 / 346
Регистрация: 10.12.2010
Сообщений: 5,468
Записей в блоге: 2
#1

Coding style или нет - C++

09.02.2012, 19:56. Просмотров 3041. Ответов 60
Метки нет (Все метки)

Услышал сегодня от коллеги такую интересную вещь: есть блоки кода ограниченные командными скобками {}. Так вот, рекомендуется переменные, используемые в блоках и только в них, объявлять в таких блоках. Я например, как правило объявляю переменные в начале подпрограмм. Привычка. Вопрос такой: это чисто coding style рекомендация или есть какое-то практическое значение подобного действия?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.02.2012, 19:56
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Coding style или нет (C++):

Ошибка с массивами, хотя формально её нет (похожи ли массивы или нет?) - C++
Всем доброго времени суток!) В общем имею такую великолепную чтуку, она должна говорить мне, похожи ли массивы или нет, массив должен...

Вывести на экран слова, в которых все символы повторяющиеся, или сообщение «Нет», если требуемых слов нет - C++
Дана последовательность символов, состоящая из слов. Вывести на экран слова, в которых все символы повторяющиеся, или сообщение «Нет», если...

Как разбить код на 2 функции: Coding и Decoding? - C++
#include <iostream> #include <vector> #include <map> #include <list> #include <fstream> using namespace std; ...

Где можго почитать о Coding Convention для C++ на русскос языке? - C++
Я не смог нагуглить.

Как найти текст в файле и возвратить 0 или 1 в зависимости от того,найдено или нет? - C++
bool fnd(char* fn,string stf) { string s; ifstream ifs(fn); while (!ifs.eof()) { getline(ifs,s); ...

Вывести True или False в зависимости от того, имеют три заданных целых числа одинаковую четность или нет - C++
Всем привет! Помогите, пожалуйста в решении задачи. Знаю, что задачи более,или менее лёгкие,но я в c++ почти ничего не смыслю, а лабы...

60
Evg
Эксперт CАвтор FAQ
17931 / 6155 / 408
Регистрация: 30.03.2009
Сообщений: 16,905
Записей в блоге: 27
09.02.2012, 22:08 #16
Цитата Сообщение от Сtrl Посмотреть сообщение
Если вы считаете, что непременным атрибутом переменной является ее имя
Ну разумеется. "x" и "px" - это переменные. То, что тебе вернуло new - это неправильно называть словом "переменная". Хотя для этого часто используют термин "динамически выделенный объект". Но это не есть эквивалент понятия "переменная"
2
Сtrl
139 / 129 / 3
Регистрация: 19.07.2011
Сообщений: 184
09.02.2012, 22:19 #17
Цитата Сообщение от Evg Посмотреть сообщение
То, что тебе вернуло new - это неправильно называть словом "переменная". Хотя для этого часто используют термин "динамически выделенный объект"
Согласен, я был не прав, это действительно не переменная. Но благодаря ссылкам с этой памятью можно работать как с переменной.
1
HighPredator
5541 / 1854 / 346
Регистрация: 10.12.2010
Сообщений: 5,468
Записей в блоге: 2
09.02.2012, 22:19  [ТС] #18
Подведу промежуточный итог: для встроенных типов не имеет значения место объявления. Для типов, имеющих конструктор/деструктор оба вызываются в блоке объявления. Все так? А, кстати, что с глобальными переменными?
0
Сtrl
139 / 129 / 3
Регистрация: 19.07.2011
Сообщений: 184
09.02.2012, 22:21 #19
Цитата Сообщение от HighPredator Посмотреть сообщение
А, кстати, что с глобальными переменными?
Они размещаются в статической памяти. На вашем месте я бы их избегал.
1
Evg
Эксперт CАвтор FAQ
17931 / 6155 / 408
Регистрация: 30.03.2009
Сообщений: 16,905
Записей в блоге: 27
09.02.2012, 22:26 #20
Цитата Сообщение от Сtrl Посмотреть сообщение
Но благодаря ссылкам с этой памятью можно работать как с переменной
Да. Но только по косвенности (т.е. через указатель). В то время, как к переменной можно обратиться напрямую (т.е., условно говоря, по заранее известному для компилятора месту)

Цитата Сообщение от HighPredator Посмотреть сообщение
Подведу промежуточный итог: для встроенных типов не имеет значения место объявления
С точки зрения построения кода - да (а для Си ещё и для любого типа, а не только для встроенного). С точки зрения удобства, стиля и т.п. - нет.

Цитата Сообщение от Сtrl Посмотреть сообщение
На вашем месте я бы их избегал
Более правильным было бы сказать, что по возможности надо строить программу так, чтобы не было глобальных переменных. Но не доводить до фанатизма и не писать лишние килобайты кода только ради того, чтобы не было одной глобальной переменной
1
HighPredator
5541 / 1854 / 346
Регистрация: 10.12.2010
Сообщений: 5,468
Записей в блоге: 2
09.02.2012, 22:32  [ТС] #21
Осознал. Всем спасибо!
0
Байт
Эксперт C
16133 / 10411 / 1549
Регистрация: 24.12.2010
Сообщений: 19,712
09.02.2012, 23:07 #22
Цитата Сообщение от AzaKendler Посмотреть сообщение
какое то время они лежат нетронутыми пока в стеке есть место.
Они лежат нетронутыми до вызова другой функции или входа в другой блок.
Представь себе стек, как стопку книг. Из блока (функции) выходим - книжка (автоматические переменные) снимается. Входим в другую - на стопку кладется ее брошюрка.
2
Bers
Заблокирован
10.02.2012, 08:00 #23
Цитата Сообщение от Сtrl Посмотреть сообщение
C++
1
2
3
4
5
// плохой код
int n, i, sum;
sum = 0;
for (i = 0, n = 10; i < n; i++)
  sum += i;
А такой?
C++
1
2
3
4
5
6
7
int sum=0; const size_t n=10;
for (size_t i = 0; i < n; i++)
{
     CBar bar;  //предположим, дорогое создание
                   //за пределами цикла не используется.
     sum +=  bar.Work(); 
}
А такой?
C++
1
2
3
4
int sum=0; const size_t n=10;
CBar bar;  //предположим, дорогое создание
              //за пределами цикла не используется.
for (size_t i = 0; i < n; i++)   sum +=  bar.Work();
А такой?
C++
1
2
3
4
5
6
7
int sum=0; 
{
    const size_t n=10;
    CBar bar;  //предположим, дорогое создание
                 //за пределами цикла не используется.
    for (size_t i = 0; i < n; i++)   sum +=  bar.Work(); 
}
Лично я использую вот такую каноническую форму:
C++
1
2
3
4
5
6
7
8
void Foo()
{
    //Зона объявлений всех участников алгоритма
 
    //Зона боевых действий
 
    //Зона чистки
}
При этом действует правило "близкого объявления". То бишь, где объявил, там и используй.
Однако, все объявления - только в зоне объявлений участников.

Получается, если запрещаю себе создавать сущности непосредственно по месту использования в боевом коде (за искл. индексов циклов for, значения которых не используется после окончания цикла), то как же мне суметь выдержать правило "близкого объявления" ?

Очень просто - не раздувать тело функции. Если используемая переменная оказывается слишком далеко от места объявления, значит функция "слишком раздутая". Это красноречивый признак говнокодистости.

Значит стоит подумать о том, что алгоритм слишком тяжелый, и возможно он решает не одну задачу, а множество задач. И стоит прочистить его структуру - разбить большую сложную задачу на кучку мелких.

Весь мой код внешне состоит из 100500 функций, и все - мелкие. Редко когда туловище функции-члена не влазит целиком на страничку моего экрана. Поэтому всегда можно окинуть мысленным взором функцию целиком. Сразу понять, что она делает. Если нужно при этом ещё понять, как она это делает - можно глянуть какие функции она дергает, что бы увидеть их непосредственную реализацию.
Получается, что код читается по принципу: сначала "что делает функция?", затем "как она это делает?"
Такой код не сложно читать.

С другой стороны, если создавать сущности не в зоне объявлений, а непосредственно по месту использования - такой подход сделает "комфортным" процесс раздувания туловища функций, хоть до бесконечности.

В результате получаются функции-тяжеловесы из 100500 строк, которые уже не отвечает на вопросы "что они делают". А сразу отвечают на вопросы "как они делают нечто".

Не зная "что", ответ на вопрос "как" становится уже не очевиден. Такой код труднее понять.
А учитывая, что такие "раздутые" алгоритмы решают сразу несколько задач - труднее вдвойне.
0
Evg
Эксперт CАвтор FAQ
17931 / 6155 / 408
Регистрация: 30.03.2009
Сообщений: 16,905
Записей в блоге: 27
10.02.2012, 09:43 #24
Цитата Сообщение от Bers Посмотреть сообщение
При этом действует правило "близкого объявления". То бишь, где объявил, там и используй.
Однако, все объявления - только в зоне объявлений участников
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void func (void)
{
  std::string str = "abc";
  str += "efg";
  func2 (str);
 
  // Далее идёт большое количество кода, которое уже не использует переменную str
  // Если бы мы верхние три строки облачили в фигурные скобки, что деструктор str
  // вызвался бы сразу и освободил лишнюю память, занятую строкой. Но теперь
  // деструктор вызовется только в конце процедуры, а потребляемая string'ом память
  // всё это время будет висеть мёртвым грузом. Это одно из тех удобств Си++, которое
  // мне не нравится из-за того, что у программиста нет удобных средств для контролирования
  // за этим процессом
  ...
 
}
Цитата Сообщение от Bers Посмотреть сообщение
Если используемая переменная оказывается слишком далеко от места объявления, значит функция "слишком раздутая". Это красноречивый признак говнокодистости
Цитата Сообщение от Bers Посмотреть сообщение
И стоит прочистить его структуру - разбить большую сложную задачу на кучку мелких
Абсолютный бред, основанный на том, что ты пока не имел опыта в написании большого и сложного софта
1
Bers
Заблокирован
10.02.2012, 10:09 #25
Evg
C++
1
2
3
4
5
6
7
8
void func (void) {  std::string str = "abc"; str += "efg";  func2 (str); }
 
void bar(void)
{
  // Далее идёт большое количество кода, которое уже не использует переменную str
  // И даже не подозревает о её существовании
  ...
}
Вообще, формулировка "большое количество кода" намекает, что "код делает очень многое".
Получаем функцию, которая выполняет не одну конкретную задачу, а множество разных задач.
Выглядит это все как монолитная размазня на 100500 строк.

Цитата Сообщение от Evg Посмотреть сообщение
Абсолютный бред, основанный на том, что ты пока не имел опыта в написании большого и сложного софта
Просто мир не совершенен. А в несовершенном мире говнокод оказывается жизнеспособнее красивого кода. Потому что тупо некогда заниматься красивостями. Потому что порой он слишком часто меняется, и нет смысла тратить много времени на то, что с высокой степенью вероятности нужно будет править.

В реальном мире масштабируемая архитектура на весь золота. Потому что позволяет нивелировать потенциальный вред от говнокода за счет продуманной техники его инкапсуляции.

Однако и в реальном мире есть показательные примеры. Допустим библиотека LOKI и STL как небо и земля.
В LOKI сможет разобраться даже тот программист, который имеет только базовые знания о шаблонах, даже не читая документации.
В STL без 100 грамм реально не разберёшься.

http://cs10041.vk.com/u226973/144727247/y_1385123a.jpg

А что до меня - я много раз наблюдал за собой такой эффект, когда трудно становится удержать в голове алгоритм выполнения задачи. И чем дальше в лес - тем сложнее. Для меня это сигнал, что нужно остановится, и подумать, как сложную задачу раздробить на кучку мелких.
"Разделяй и властвуй".
0
AzaKendler
214 / 116 / 9
Регистрация: 30.05.2011
Сообщений: 1,772
10.02.2012, 11:58 #26
Цитата Сообщение от Evg Посмотреть сообщение
Если бы мы верхние три строки облачили в фигурные скобки,
спасибо. не обращал внимание. это обрезает область видимости оказывается. просто скобки.
интересный момент


Цитата Сообщение от Evg Посмотреть сообщение
. Но теперь
// деструктор вызовется только в конце процедуры, а потребляемая string'ом память
// всё это время будет висеть мёртвым грузом. Это одно из тех удобств Си++, которое
// мне не нравится из-за того, что у программиста нет удобных средств для контролирования
// за этим процессом
C++
1
str.~basic_string();
не подойдет для такого управления?
0
soon
2541 / 1306 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
10.02.2012, 12:18 #27
Цитата Сообщение от AzaKendler Посмотреть сообщение
не подойдет для такого управления?
Не надо деструкторы где попало вызывать. Даже не так. Вообще не надо деструкторы вызывать.
code
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
soon@desktop:~/Src/C++/main$ cat main.cpp
#include <string>
 
int main()
{
    std::string str("asd");
    str.~basic_string();
    return 0;
}
soon@desktop:~/Src/C++/main$ g++ main.cpp -o main && ./main
*** glibc detected *** ./main: double free or corruption (fasttop): 0x09d04008 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x6ebc2)[0x899bc2]
/lib/i386-linux-gnu/libc.so.6(+0x6f862)[0x89a862]
/lib/i386-linux-gnu/libc.so.6(cfree+0x6d)[0x89d94d]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xe8180f]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSs4_Rep10_M_destroyERKSaIcE+0x1b)[0xe68c4b]
/usr/lib/i386-linux-gnu/libstdc++.so.6(+0x94c8c)[0xe68c8c]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSsD1Ev+0x2e)[0xe68cfe]
./main[0x80486a7]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x844113]
./main[0x8048581]
======= Memory map: ========
001ef000-001f0000 r-xp 00000000 00:00 0          [vdso]
00411000-00439000 r-xp 00000000 08:01 5899205    /lib/i386-linux-gnu/libm-2.13.so
00439000-0043a000 r--p 00028000 08:01 5899205    /lib/i386-linux-gnu/libm-2.13.so
0043a000-0043b000 rw-p 00029000 08:01 5899205    /lib/i386-linux-gnu/libm-2.13.so
0082b000-009a1000 r-xp 00000000 08:01 5899175    /lib/i386-linux-gnu/libc-2.13.so
009a1000-009a3000 r--p 00176000 08:01 5899175    /lib/i386-linux-gnu/libc-2.13.so
009a3000-009a4000 rw-p 00178000 08:01 5899175    /lib/i386-linux-gnu/libc-2.13.so
009a4000-009a7000 rw-p 00000000 00:00 0 
00afb000-00b19000 r-xp 00000000 08:01 5899162    /lib/i386-linux-gnu/ld-2.13.so
00b19000-00b1a000 r--p 0001d000 08:01 5899162    /lib/i386-linux-gnu/ld-2.13.so
00b1a000-00b1b000 rw-p 0001e000 08:01 5899162    /lib/i386-linux-gnu/ld-2.13.so
00d52000-00d6e000 r-xp 00000000 08:01 5899196    /lib/i386-linux-gnu/libgcc_s.so.1
00d6e000-00d6f000 r--p 0001b000 08:01 5899196    /lib/i386-linux-gnu/libgcc_s.so.1
00d6f000-00d70000 rw-p 0001c000 08:01 5899196    /lib/i386-linux-gnu/libgcc_s.so.1
00dd4000-00eb2000 r-xp 00000000 08:01 3806517    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
00eb2000-00eb3000 ---p 000de000 08:01 3806517    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
00eb3000-00eb7000 r--p 000de000 08:01 3806517    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
00eb7000-00eb8000 rw-p 000e2000 08:01 3806517    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
00eb8000-00ebf000 rw-p 00000000 00:00 0 
08048000-08049000 r-xp 00000000 08:01 797557     /home/soon/Src/C++/main/main
08049000-0804a000 rw-p 00000000 08:01 797557     /home/soon/Src/C++/main/main
09d04000-09d25000 rw-p 00000000 00:00 0          [heap]
b7700000-b7721000 rw-p 00000000 00:00 0 
b7721000-b7800000 ---p 00000000 00:00 0 
b78be000-b78c1000 rw-p 00000000 00:00 0 
b78d2000-b78d4000 rw-p 00000000 00:00 0 
bfa57000-bfa78000 rw-p 00000000 00:00 0          [stack]
Aborted
soon@desktop:~/Src/C++/main$ cat main1.cpp
#include <string>
 
int main()
{
    std::string str("asd");
    return 0;
}
soon@desktop:~/Src/C++/main$ g++ main1.cpp -o main && ./main
soon@desktop:~/Src/C++/main$
0
AzaKendler
214 / 116 / 9
Регистрация: 30.05.2011
Сообщений: 1,772
10.02.2012, 12:58 #28
как видишь чисто. и никаких ругательств при сборке не было

дело в том что их не надо где попало вызывать не думая. но их вызов вполне возможен и нужен если необходимо управлять процессом. например аллокаторы они очень даже вызывают деструкторы.

да и сам ты если поместишь объект в какую то "свою" область то потом обязан будешь вызвать деструктор самостоятельно а не просто уничтожить область.


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Test
{
    Test():a(40){};
    ~Test(){};
    int a;
};
 
int main()
{
 
    char* b = new char [100];
    Test* s = new(b) Test;
 
    s->a =7 ;
    s->~Test();
    delete [] b;
    return 0;
}
0
Миниатюры
Coding style или нет  
soon
2541 / 1306 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
10.02.2012, 13:06 #29
Цитата Сообщение от AzaKendler Посмотреть сообщение
и никаких ругательств при сборке не было
При сборке и не будет.

Цитата Сообщение от AzaKendler Посмотреть сообщение
да и сам ты если поместишь объект в какую то "свою" область то потом обязан будешь вызвать деструктор самостоятельно а не просто уничтожить область.
Пример можете привести?
0
AzaKendler
214 / 116 / 9
Регистрация: 30.05.2011
Сообщений: 1,772
10.02.2012, 13:11 #30
Цитата Сообщение от soon Посмотреть сообщение
Пример можете привести
привел выше. он конечно оторван от реальности. но при разборе темы с контейнерами и в частности с аллокаторами - эта тема с вызовом деструктора часто всплывает. более того в опрераторе delete предусмотрен все тот же явный вызов деструктора
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.02.2012, 13:11
Привет! Вот еще темы с ответами:

Опечатка или нет? - C++
class my_class { public: my_class() { a = b = 0; } my_class(constint...

симафор или нет? - C++
ПРивет всем! написал программу для следующего задания с использованием симафора: Написать программу, создающую два потока. Оба...

C++11 в production, да или нет? - C++
Всем привет. Выбил все-таки разрешение юзать С++11 на работе, по мелочи, лямбды вместо предикатов, range-based-for, auto. Сегодня наш тех....

Палиндром или нет? - C++
Определить, является ли заданное натуральное число палиндромом, т.е. таким, десятичная запись которого читается одинаково слева направо и...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
30
Yandex
Объявления
10.02.2012, 13:11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru