Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.72/25: Рейтинг темы: голосов - 25, средняя оценка - 4.72
 Аватар для HighPredator
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3

Coding style или нет

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

Студворк — интернет-сервис помощи студентам
Услышал сегодня от коллеги такую интересную вещь: есть блоки кода ограниченные командными скобками {}. Так вот, рекомендуется переменные, используемые в блоках и только в них, объявлять в таких блоках. Я например, как правило объявляю переменные в начале подпрограмм. Привычка. Вопрос такой: это чисто coding style рекомендация или есть какое-то практическое значение подобного действия?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
09.02.2012, 19:56
Ответы с готовыми решениями:

border-style нет нужного
Не нашел такого стиля чтобы например я делаю черным рамку,4 px, первый слой абсолютно черный(000) по всему периментру, след. чуть...

canvas.не меняется brush.style & pen.style
На форме лежит имэдж нужно часть его обвести (это в идеале). Я это решил реализовать так поместить сверху другой имэг и на его канве...

Как удалить стиль определенный между <style></style>
Привет. Есть тестовый пример : #foo{color:green;} &lt;div id=&quot;foo&quot; style=&quot;color:red&quot;&gt;hello&lt;/div&gt; Как очистить стили...

60
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21287 / 8312 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
10.02.2012, 14:08
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от AzaKendler Посмотреть сообщение
я как раз про это и писал в примере. когда в классе есть указатель на динамически созданный объект, а деструкторе его удаление и обнуление указателя
Ну и чтобы инициализация-деинициализация была в руках программиста, нужно либо все экземпляры создавать динамически, либо заниматься онанизмом и использовать placement new (в качестве буфера можно использовать обычный локальный массив, не прибегая к динамической памяти). В обоих случаях всё сводится к тому, что нужно извращаться.
0
Заблокирован
10.02.2012, 14:10
Цитата Сообщение от Evg Посмотреть сообщение
... Но эти три строки кода будут работать долго. И всё это время память для уже ненужного объекта будет висеть занятой. Только потому, что это как бы красиво выглядит в исходнике
Ну ежели, это не критично для всего приложения - почему бы и нет? Они жить не мешают. А вот красивость - это бонус.

Но у меня другой подход - бритва Оккама. Если можно что то не делать - этого делать не нужно.
Если данному куску кода не нужен данный объект, то нет ни одной причины вообще создавать этот ненужный объект.

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

Иногда бывают особые моменты, когда могут потребоваться дополнительные временные объекты.
На самом деле требуются некие услуги, которые можно через них поиметь, а не сами объекты.
Можно просто сделать отдельную inline функцию, на которую свалить задачу по предоставлению данной услуги. Это оградит основной алгоритм от ненужных ему подробностей реализации, и избавит от присутствия совершенно не нужных ему временных объектов:

//здесь кучка кода
...
выходные_данные = foo(входные); //мелкая услуга
...
//остальной код
...
выходные_данные = foo(входные); //ещё какая нибудь мелкая услуга
...

С точки зрения "большого" куска кода, все объекты которые он используют - нужны.
Временных, или лишних не существует. Как работают мелкие поставщики услуг - их собственные трудности.
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 14:14
Цитата Сообщение от Evg Посмотреть сообщение
Ну и чтобы инициализация-деинициализация была в руках программиста, нужно либо все экземпляры создавать динамически, либо заниматься онанизмом и использовать placement new (в качестве буфера можно использовать обычный локальный массив, не прибегая к динамической памяти). В обоих случаях всё сводится к тому, что нужно извращаться.
C++
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
class Foo
{
    int* _ptr;
 
public:
    Foo(): _ptr(new int[10000])
    {
 
    }
 
    ~Foo()
    {
        delete [] _ptr;
        _ptr = 0;
    }
};
 
int main()
{
    Foo f;
 
//код
 
//а тут надо очень очень очень сэкономить и избавиться от того что висит в памяти. 
    f.~Foo();
//это все скорее неправильно и лучше сделать очищающую функцию, но речь об том как деструктором
//код
//код
//код
 
    return 0;
}
и правда не очень все это. но возможность есть
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21287 / 8312 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
10.02.2012, 14:23
Цитата Сообщение от Bers Посмотреть сообщение
Ну ежели, это не критично для всего приложения - почему бы и нет? Они жить не мешают. А вот красивость - это бонус
А это и есть причина появления гавнокода. Тут оказалось не совсем критичным, там окзалось не совсем критичным. А потом наберётся этих ситуаций целая куча и программа начинает работать в два раза медленнее и жрать памяти в два раза больше

Цитата Сообщение от Bers Посмотреть сообщение
Если данному куску кода не нужен данный объект, то нет ни одной причины вообще создавать этот ненужный объект.
Дык проблема в том, что он был нужен чуть ранееи дальше появляется точка, где от объекта уже можно избавиться, т.к. по результату его использования было вычислено нужное значение, которое будет использовано в цикле из миллиона итераций. Я использую в примере string весьма условно (просто как некий экземпляр некоего класса)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void func1 (int x1, int x2, int x3)
{
  std::string str;
 
  str += x1;
  str += x2;
  str += x3;
 
  int len = str.length();
 
  // Здесь str нам больше не нужен. Но поскольку у тебя принципиально нет никаких
  // переменных влексических блоках, то на время работы цикла память, отжираемая
  // экземпляром str, будет необоснованно болтаться как использованная
 
  for (i = 0; i < 1000000; i++)
    func2 (len);
}
Далее по твоей логике код работы с str надо выносить в отдельную функцию, в которую передать три параметра. Ну это в моём простом случае параметрв три, а может быть их и больше. Могут быть промежуточные значения, которые используются в виде локалов данной функции, которые придётся передавать в функцию. Могут быть несколько объектов типа str. И в итоге из-за принципиальных соображений один нормально читаемый код в виде одной нормально читаемой функции првреатится в десяток функций, в которых ориентироваться будет намного сложнее.

Добавлено через 4 минуты
Цитата Сообщение от AzaKendler Посмотреть сообщение
но возможность есть
Так твой код не рабочий. Он работает по счастливой случайности, что в дестркуторе ты вставил "_ptr=0", из-за чего повторный вызов "delete [] _ptr" не сломался. А ты воткни в деструктор печать, работу с файлом или чем-нибудь ещё, что имеет внешнее проявление. И увидишь, что завершающие действия у тебя выполняются два раза вместо одного
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 14:32
Evg
Так твой код не рабочий. Он работает по счастливой случайности, что в дестркуторе ты вставил "_ptr=0", из-за чего повторный вызов "delete [] _ptr" не сломался. А ты воткни в деструктор печать, работу с файлом или чем-нибудь ещё, что имеет внешнее проявление. И увидишь, что завершающие действия у тебя выполняются два раза вместо одного
он рабочий только потому что обнулен указатель. да деструктор вызовется 2 раза. и 2 раза выйдет на печать бодяга.
но ты ведь вел речь об экономии памяти в стринге ну и о том что он будет висеть до конца процедуры. для этого там есть clear(). и динамическая память очистится. с деструкторами это уже так полезли не в ту сторону. изначальная мысль - в с++ нет удобных средств для очистки памяти пока идет выполнение программы со строкой из твоего примера. возражаю они ЕСТЬ, это либо предусмотренные функции очистки в библиотченых классах. либо кривизна с деструктором.
ну а сам по себе стринг много места не занимает - ты сам писал. и уж если и это критично то можно не использовать стринг.
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
10.02.2012, 14:34
AzaKendler, никогда не обнулял указатель в деструкторе. Потому что не для того деструктор предназначен, чтобы когда нам заблагорассудится вызывался. Он должен вызываться для одного объекта один раз, при уничтожении, и точка. Это как с const_cast. Он вроде как есть, и его даже вроде как можно использовать, но если из-за него программа свалится в рантайме, то программист сам дурак.
Ну и плюс к тому, в своих классах можно обо всём позаботиться (напихать ключей, которые будут говорить, закрыт ли файл, разорвано ли соединение, очищена ли память, и проверять всё это в деструкторе), но проблема в том, что мы чаще используем чужой код, а не собственный. И при этом надо знать, что деструктор не предназначен для вызова вручную, и что если такой вызов будет иметь и место и затем будет иметь место падение в рантайме, то программист снова сам дурак.
0
Заблокирован
10.02.2012, 14:36
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int GetLenth(int x1, int x2, int x3) 
{ 
    std::string str; str +=x1; str +=x2; str +=x3; 
    return str.size(); 
}
 
void func1 (int x1, int x2, int x3)
{
  int len = GetLenth(x1,x2,x3);
 
  // Здесь str нам больше не нужен. 
 
  for (i = 0; i < 1000000; i++)
    func2 (len);
}
Цитата Сообщение от Evg Посмотреть сообщение
Могут быть промежуточные значения
Ну вот, по поводу промежуточных значений...

Иногда, исключительно для читабельности, есть смысл завести промежуточный объект.
Но это переменные типа int какие нибудь...

Если же в качестве такого промежуточного объекта просится очень тяжелый объект - явно что то не в порядке в самой архитектуре.

Пример того, чего быть не должно:

MyClass a,b; //оч тяжелые объекты
...
MyClass c = a; a=b; b=c;

Пример того, что должно быть:
a.Swap(b); //перенацелятся лишь парочка указателей. Никакого копирования.

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


Цитата Сообщение от Evg Посмотреть сообщение
И в итоге из-за принципиальных соображений один нормально читаемый код в виде одной нормально читаемой функции превратится в десяток функций, в которых ориентироваться будет намного сложнее.
Этого не может быть. Есть только два варианта:
1. Весь код представляет собой монолитную размазню.
2. Код разбит на функции.

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

Можно написать все в теле одной мега-раздутой функции. Можно разбить на десяток мелких.
Но само по себе "количество" кода либо не изменится, либо уменьшится, но только в случае разбиения на функции.
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 14:36
silent_1991, немного смысл утерян диалога. я выше в посте пометил почему началась эта тема.
конечно деструктор не нужно дергать дела без дела, а нужно только при необходимости/
А обнулять указатели надо по любому. поскольку в с++ delete нулевого указателя - это не ошибка, просто ничего не делается
а вот не обнуленного но уже ссылающегося на очищенную память - краш
0
Почетный модератор
7393 / 2639 / 281
Регистрация: 29.07.2006
Сообщений: 13,696
10.02.2012, 14:45
Evg, Bers прав... Если функция настолько велика, что вынуждает объявлять переменные в ее середине (без явных на то оснований), то это уже "говнокод". От величины и сложности проекта не зависящий.
Цитата Сообщение от Evg Посмотреть сообщение
один нормально читаемый код в виде одной нормально читаемой функции првреатится в десяток функций
Лучше 10 вызовов функций с говорящими именами, чем простыня на 100 строк в одной функции, из которых 40 на комментарии.
Цитата Сообщение от Evg Посмотреть сообщение
то на время работы цикла память, отжираемая
* // экземпляром str, будет необоснованно болтаться как использованная
Это никак не скажется на работе программы. (если только в следующих вызовах не соберемся стек переполнить, что получится сделать немного быстрее)
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21287 / 8312 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
10.02.2012, 14:52
Цитата Сообщение от AzaKendler Посмотреть сообщение
но ты ведь вел речь об экономии памяти в стринге
string я использовал как пример экземпляра класса для наглядности. На его месте может быть любой самодельный класс, активно потребляющий память и работающий с файлами

Bers, вот тебе фрагмент отладчика gdb: файл infrun.c. См. функцию handle_inferior_event. Это одна большая логическая последоваттельность действий, которая потеряет всякую логику, будучи искусственно разбитой на маленькие запчасти

Добавлено через 1 минуту
Цитата Сообщение от Vourhey Посмотреть сообщение
Это никак не скажется на работе программы. (если только в следующих вызовах не соберемся стек переполнить, что получится сделать немного быстрее)
Я уже говорил, что string - условность. Это может быть экземпляр произсольного класса, который отожрал 10 мегабайт динамической памяти и которая освободится только при удалении объекта
0
Заблокирован
10.02.2012, 14:55
Цитата Сообщение от AzaKendler Посмотреть сообщение
А обнулять указатели надо по любому. поскольку в с++ delete нулевого указателя - это не ошибка, просто ничего не делается
а вот не обнуленного но уже ссылающегося на очищенную память - краш
Вот я так и не определился с мыслью: ошибка это, или нет - удалять по нулевому указателю.

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

А если бы программка тихо промолчала - стало быть, и не узнал бы я, что у меня прокрался баг.

Из этих соображений, решил я ставить ассерт перед удалением. И ежели указатель уже ноль - стало быть в дебаге мне мой код об этом поведует. А в релизе сохранит работоспособность.
1
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 15:01
Цитата Сообщение от Evg Посмотреть сообщение
который отожрал 10 мегабайт динамической памяти и которая освободится только при удалении объекта
если это самописный класс, то уже на совести того кто его писал предусмотреть аналог clear() и возможность очистки ДО удаления при выходе из области видимости.
Это уже более философский вопрос, касающийся того "а что за человек писал код".

Добавлено через 3 минуты
Bers, ну если ты предпочитаешь так проверяться то да. ты практикующий постоянно судя по всему. к тебе можно прислушаться.
но при тестах ты можешь и не найти ту ошибку которая приводит к крашу и не обнаружить какие то петли и повторные вызовы. это может произойти у клиента. ну а если будет 0, то будет работать пока ты готовишь апдейты или проводишь доп тесты.
ну это такая фантазия

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

Добавлено через 1 минуту
Цитата Сообщение от Bers Посмотреть сообщение
И ежели указатель уже ноль
все таки нулишь?
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21287 / 8312 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
10.02.2012, 15:04
Цитата Сообщение от AzaKendler Посмотреть сообщение
все таки нулишь?
Он нулит его только для того, чтобы поймать ситуацию повторного вызова деструктора. И это правильный способ.
1
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 15:05
Цитата Сообщение от Bers Посмотреть сообщение
Вот я так и не определился с мыслью: ошибка это, или нет - удалять по нулевому указателю
думаю не ошибка. указатель может быть установлен в 0 в конструкторе и ждать некой функции Init();
если инит не вызван то указатель так и будет 0, и в деструкторе будет delete 0. если инит отработает то будет что то удалено из
памяти в деструкторе как и задумывалось
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
10.02.2012, 15:05
AzaKendler, clear в том же стринге память не очищает. В векторе, например, тоже. Т.е. ни стринг, ни вектор вообще никогда не уменьшают размера. Пример:
http://liveworkspace.org/code/... 8864746f5c
Напомню, что capacity возвращает количество элементов, которое контейнер может вместить без очередного выделения памяти.
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 15:10
silent_1991, тогда resize(0). за клиар сорри. спасибо за уточнения уж если писать то точно.
имел ввиду принцип очистки до удаления. напутал функцию
0
Заблокирован
10.02.2012, 15:11
Цитата Сообщение от AzaKendler Посмотреть сообщение
все таки нулишь?
Есть два режима: дебаг, и релиз.
Дебаг - это версия для отладки. Релиз - это версия для клиента.

В дебаге ассерты срабатывают. В релизе, код проверок будит выброшен препроцессором и не будет скомпилирован.

Перед удалением у меня стоит ассерт, который сработает, если указатель нулевой.
А после удаления, соответственно, зануляет указатель.

Таким образом, в дебаге у меня будет проверка на попытку двойного удаления.
А в релизе никаких проверок вообще уже не существует. Но так как указатели зануляются, то попытка двойного удаления вреда не нанесет.

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

Тут есть свои нюансы: например, если объект в принципе имеет право "не выделять динамическую память". Допустим, при создании, он ещё пустой, и его указатель нулевой. То.. он имеет право делетить нулевой указатель.
А если объект при создании автоматически выделяет память - тогда не имеет.
1
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
10.02.2012, 15:17
AzaKendler, clear и есть resize(0). Невозможно уменьшить размер выделенной в строке памяти извне. Даже reserve(0) не поможет.

Добавлено через 1 минуту
Вру.
Можно так:
C++
1
2
str.resize(0);
str.reserve(0);
Добавлено через 1 минуту
Но это только со строкой. Вектор совершенно отказывается "расти вниз".
0
Заблокирован
10.02.2012, 15:18
silent_1991

C++
1
void ClearStr(std::string& obj) {   std::string tmp; tmp.swap(obj); }
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 15:19
silent_1991, чтож остается только swap с пустым классом
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.02.2012, 15:19

Задавать свойство лучше в style(CSS) или в HTML?
1)&lt;img alt=&quot;&quot; src=&quot;images/tuner.jpg&quot; width=&quot;250px&quot; height=&quot;250px&quot; align=&quot;right&quot;&gt; 2)&lt;img alt=&quot;&quot; src=&quot;images/tuner.jpg&quot; style=&quot;width:...

Где хранится element.style или изменить width дива
Добрый день уважаемые форумчане. Весь день бьюсь над проблемой... Сил больше нет... Подскажите. Правлю шаблон сайта. У меня 2 дива...

Присвоить div-у атрибут class или style и вписать в них данные
Здравствуйте Есть див &lt;div id='div' contenteditable=&quot;true&quot;&gt;///&lt;/div&gt; Необходимо присвоить ему атрибут class или style и вписать в них...

SOS Coding Input
Добрый день. Ребята очень нужна помощь на вас надежда. Смотрите суть такова: Если таблица в базе MYSQL на сервере. Я...

Good Coding Practices
123 Добавлено через 1 час 1 минуту Всем привет. Примитивнейшая задача: два класса обмениваются значениями переменных. Два объекта,...


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Транслитерация текста с кириллицы на латиницу
Maks 11.11.2026
Решил облегчить жизнь себе и коллегам админам при создании электронных почтовых ящиков для пользователей, в результате написал обработку "Транслитерация текста" с кириллицы на латиницу, а в ней. . .
Книги по геймдизайну, левел-дизайну, игровым механикам и проектированию игрового опыта
8Observer8 08.11.2026
Содержание блога | English Version 1. 2003 - 06 - Designing Virtual Worlds (1st Edition) Автор: Richard A. Bartle | Объем: 768 стр. Ссылки: Amazon . . .
Родители токсичные абьюзеры по отношению к своим детям ругают их оскорбляют не любят
zorxor 08.11.2026
Жить в атмосфере постоянных оскорблений, критики и холодности со стороны родителей — это тяжелое и болезненное испытание, которое оставляет глубокие эмоциональные раны. Токсичное и абьюзивное. . .
Как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Ответ от Джемени ИИ.
zorxor 08.11.2026
Джемени, как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Многие люди, возвращаясь домой, сразу переодеваются в максимально свободную одежду или вовсе предпочитают. . .
Паттерн очереди действий/команд (Action / Command Queue). Система очереди действий и кат-сцен с SDL3 Callbacks, cglm и OpenGL
8Observer8 07.11.2026
Содержание блога | English Version Руководство для начинающих по реализации паттерна очереди действий/ команд (Action / Command Queue) на C++ (C++20) с использованием официального SDL3 Callbacks. . .
Проверка полного ФИО в типовом справочнике
Maks 07.11.2026
Решение реализовано в конфигурации КА2, на примере справочника "КонтактныеЛицаПартнеров". Задача: Запрет инициалов. Не допускаеть использование сокращений вида "И. И. ", "И. И. ", "И И" и. . .
Про "Windows must die!"
kumehtar 04.11.2026
Знаете, чет накатило. . . . Когда-то это было почти боевым кличем: мол, нормальный человек сидит на DOS, OS/ 2 или Linux, а вот это вот - Must Die. А теперь человек произносит «мастдай» с усмешкой - и. . .
Красочные поля с номером страницы svg+background-image
russiannick 04.11.2026
Красочные поля с номером страницы не менее важны чем в эпоху бумажных книг. Посему спешу представить почтеннейшей публике этот важный инструмент который эти поля и формирует. В процессе разработки. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru