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

Coding style или нет

09.02.2012, 19:56. Показов 5933. Ответов 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
 Аватар для HighPredator
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
09.02.2012, 22:32  [ТС]
Студворк — интернет-сервис помощи студентам
Осознал. Всем спасибо!
0
Диссидент
Эксперт C
 Аватар для Байт
27714 / 17332 / 3810
Регистрация: 24.12.2010
Сообщений: 38,978
09.02.2012, 23:07
Цитата Сообщение от AzaKendler Посмотреть сообщение
какое то время они лежат нетронутыми пока в стеке есть место.
Они лежат нетронутыми до вызова другой функции или входа в другой блок.
Представь себе стек, как стопку книг. Из блока (функции) выходим - книжка (автоматические переменные) снимается. Входим в другую - на стопку кладется ее брошюрка.
2
Заблокирован
10.02.2012, 08:00
Цитата Сообщение от С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
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,670
Записей в блоге: 30
10.02.2012, 09:43
Цитата Сообщение от 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
Заблокирован
10.02.2012, 10:09
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/... 85123a.jpg

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


Цитата Сообщение от Evg Посмотреть сообщение
. Но теперь
// деструктор вызовется только в конце процедуры, а потребляемая string'ом память
// всё это время будет висеть мёртвым грузом. Это одно из тех удобств Си++, которое
// мне не нравится из-за того, что у программиста нет удобных средств для контролирования
// за этим процессом
C++
1
str.~basic_string();
не подойдет для такого управления?
0
 Аватар для soon
2554 / 1319 / 178
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
10.02.2012, 12:18
Цитата Сообщение от 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 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 12:58
как видишь чисто. и никаких ругательств при сборке не было

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

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


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;
}
Миниатюры
Coding style или нет  
0
 Аватар для soon
2554 / 1319 / 178
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
10.02.2012, 13:06
Цитата Сообщение от AzaKendler Посмотреть сообщение
и никаких ругательств при сборке не было
При сборке и не будет.

Цитата Сообщение от AzaKendler Посмотреть сообщение
да и сам ты если поместишь объект в какую то "свою" область то потом обязан будешь вызвать деструктор самостоятельно а не просто уничтожить область.
Пример можете привести?
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 13:11
Цитата Сообщение от soon Посмотреть сообщение
Пример можете привести
привел выше. он конечно оторван от реальности. но при разборе темы с контейнерами и в частности с аллокаторами - эта тема с вызовом деструктора часто всплывает. более того в опрераторе delete предусмотрен все тот же явный вызов деструктора
0
 Аватар для soon
2554 / 1319 / 178
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
10.02.2012, 13:24
Цитата Сообщение от AzaKendler Посмотреть сообщение
привел выше.
А от s память освобождать не надо?
К тому же он не отображает сути проблемы, возникшей при вызове ~basic_string().
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
62
63
64
soon@desktop:~/Src/C++/main$ cat main1.cpp
class Foo
{
    int* _ptr;
 
public:
    Foo(): _ptr(new int(3))
    {
 
    }
 
    ~Foo()
    {
        delete _ptr;
    }
};
 
int main()
{
    Foo f;
    f.~Foo();
    return 0;
}
soon@desktop:~/Src/C++/main$ g++ main1.cpp -o main && ./main
*** glibc detected *** ./main: double free or corruption (fasttop): 0x09d64008 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x6ebc2)[0xd24bc2]
/lib/i386-linux-gnu/libc.so.6(+0x6f862)[0xd25862]
/lib/i386-linux-gnu/libc.so.6(cfree+0x6d)[0xd2894d]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xbbc80f]
./main[0x8048613]
./main[0x80485cf]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xccf113]
./main[0x80484d1]
======= Memory map: ========
00461000-0047f000 r-xp 00000000 08:01 5899162    /lib/i386-linux-gnu/ld-2.13.so
0047f000-00480000 r--p 0001d000 08:01 5899162    /lib/i386-linux-gnu/ld-2.13.so
00480000-00481000 rw-p 0001e000 08:01 5899162    /lib/i386-linux-gnu/ld-2.13.so
00773000-0078f000 r-xp 00000000 08:01 5899196    /lib/i386-linux-gnu/libgcc_s.so.1
0078f000-00790000 r--p 0001b000 08:01 5899196    /lib/i386-linux-gnu/libgcc_s.so.1
00790000-00791000 rw-p 0001c000 08:01 5899196    /lib/i386-linux-gnu/libgcc_s.so.1
009ae000-009d6000 r-xp 00000000 08:01 5899205    /lib/i386-linux-gnu/libm-2.13.so
009d6000-009d7000 r--p 00028000 08:01 5899205    /lib/i386-linux-gnu/libm-2.13.so
009d7000-009d8000 rw-p 00029000 08:01 5899205    /lib/i386-linux-gnu/libm-2.13.so
00b0f000-00bed000 r-xp 00000000 08:01 3806517    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
00bed000-00bee000 ---p 000de000 08:01 3806517    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
00bee000-00bf2000 r--p 000de000 08:01 3806517    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
00bf2000-00bf3000 rw-p 000e2000 08:01 3806517    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
00bf3000-00bfa000 rw-p 00000000 00:00 0 
00cb6000-00e2c000 r-xp 00000000 08:01 5899175    /lib/i386-linux-gnu/libc-2.13.so
00e2c000-00e2e000 r--p 00176000 08:01 5899175    /lib/i386-linux-gnu/libc-2.13.so
00e2e000-00e2f000 rw-p 00178000 08:01 5899175    /lib/i386-linux-gnu/libc-2.13.so
00e2f000-00e32000 rw-p 00000000 00:00 0 
00f5d000-00f5e000 r-xp 00000000 00:00 0          [vdso]
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
09d64000-09d85000 rw-p 00000000 00:00 0          [heap]
b7600000-b7621000 rw-p 00000000 00:00 0 
b7621000-b7700000 ---p 00000000 00:00 0 
b779f000-b77a2000 rw-p 00000000 00:00 0 
b77b3000-b77b5000 rw-p 00000000 00:00 0 
bf8b6000-bf8d7000 rw-p 00000000 00:00 0          [stack]
Aborted
soon@desktop:~/Src/C++/main$
0
Заблокирован
10.02.2012, 13:30
Цитата Сообщение от soon Посмотреть сообщение
К тому же он не отображает сути проблемы, возникшей при вызове ~basic_string().
В приведенном коде, проблема не в том, что был явно вызван диструктор. А в том, что он в принципе был неправильно записан. Указатель не был переведён в "не рабочее" состояние.
Если бы программист после удаления, занулил бы его, то повторный вызов диструктора не привел бы к трагедии.

Что до самих явно вызываемых диструкторов, имхо - это плохая идея, если конечно, вы не пишите какой нибудь пул памяти с new placement
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 13:35
Цитата Сообщение от soon Посмотреть сообщение
А от s память освобождать не надо?
не надо - это синтаксис размещения.
и в данном случае s->~Test() служит для очистки, на тот случай если в Test() были переменные указывающие на динамически созданные объекты.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct Test
{
        Test():a(40){};
        ~Test(){};
        int a;
};
 
 
int main()
{ 
        char* b = new char [100];
        Test* s = new(b) Test; 
      
        //s->~Test();
        delete [] b;// в этом пример оператор "зачистит" и члены тест.
        return 0;
}

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Test
{
        Test():a(new int(40)){};
        ~Test(){delete a; a=0;};
        int* a;
};
 
int main()
{ 
        char* b = new char [100];
        Test* s = new(b) Test; 
      
        s->~Test();
        delete [] b;// в этом пример оператор не сможет сам провести очистку вызов деструктора обязателен
        return 0;
}
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,670
Записей в блоге: 30
10.02.2012, 13:46
Цитата Сообщение от Bers Посмотреть сообщение
Вообще, формулировка "большое количество кода" намекает, что "код делает очень многое"
Я не совсем правильно выразился. У тебя там может быть и три строки кода, которые в цикле из миллиона итераций вызывают другую функцию, в которой вызываются ещё функции и т.п. Но эти три строки кода будут работать долго. И всё это время память для уже ненужного объекта будет висеть занятой. Только потому, что это как бы красиво выглядит в исходнике

Цитата Сообщение от Bers Посмотреть сообщение
А в несовершенном мире говнокод оказывается жизнеспособнее красивого кода. Потому что тупо некогда заниматься красивостями
Как раз-таки нет. Дофига ситуаций, когда распиливание одной процедуры на более мелкие приводит к гавнокоду. Поэтому нельзя к программированию подходить со всякими догмами типа "функция ДОЛЖНА быть короткой", "НЕЛЬЗЯ использовать goto" и т.д. В каждом конкретном случае надо принимать конкретное решение, являющееся оптимальным в данном конкретном случае

Цитата Сообщение от AzaKendler Посмотреть сообщение
спасибо. не обращал внимание. это обрезает область видимости оказывается. просто скобки.
интересный момент
Не просто область видимости, но ещё и время жизни автоматического объекта

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool x;
 
// Допустим, так сложилось, что во время работы нашей программы "x" всегда
// равно "false" (пользователь не пытался использоватьнекоторые фичи программы)
x = false;
...
 
if (x)
{
  // В этот блок мы никогда не попадём, а следовательно, объект никогда не будет
  // создан (т.е. никогда для него не вызовутся конструктор и деструктор). Это справедливо
  // как для автоматического объекта, так и для статического, который помещён вовнутрь
  // лексического блока. Т.е. сэкономили память и время исполнения
  std::string str;
  ...
}
Цитата Сообщение от AzaKendler Посмотреть сообщение
не подойдет для такого управления?
Не подойдёт, потому что компилятор по достижении закрывающей фигурной скобки автоматически влепит вызов деструктора (и на это ты повлиять никак не можешь). Таким образом, у тебя будет два вызова деструктора. Деструктор ручками можно вызывать ТОЛЬКО в том случае, если динамический объект создавался при помощи конструкции "placement new"
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 13:48
soon, конкретно по твоей ошибке тебе написали уже


C++
1
2
3
4
5
~Foo()
    {
        delete _ptr;
        _ptr = 0; // обнуляем и второй вызов пройдет безболезненно
    }
пробуй

Добавлено через 2 минуты
Цитата Сообщение от Evg Посмотреть сообщение
Деструктор ручками можно вызывать ТОЛЬКО в том случае
ну вот мы вызываем же в примерах.

и если кровь из носа надо очистить память на которую ссылаются члены класса то вызов деструктора в том месте сделает это. а то что он вызовется второй раз в холостую это конечно не очень хорошо, но краша не будет если в самом деструкторе все ровно, наверно это и имелось ввиду под неудобством?
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
10.02.2012, 13:56
AzaKendler, деструктор не предназначен для того, чтобы вызывать его вручную. Соответственно обнулять указатель в нём просто так никто не будет, а из этого и следует падение программы, когда пытаемся к указателю на память, которая уже не принадлежит программе, применить delete.
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 13:58
Цитата Сообщение от silent_1991 Посмотреть сообщение
деструктор не предназначен для того, чтобы вызывать его вручную. Соответственно обнулять указатель в нём просто так никто не будет
что то ты меня удивил. как это обнулять никто не будет - этож золотое правило для экспертов с++.
почему не предназначен, можешь растолковать?
он постоянно вызывается вручную в stl.
только мы как пользователи, например vector, это не видим, если не захотим пройтись в дебаге по всему что там происходит, ну или почитать про это
0
Эксперт С++
5058 / 3118 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
10.02.2012, 14:00
AzaKendler, он вызывается вручную в стл в аллокаторае. А вам уже не раз написали, что аллокатор для создания объекта использует placement new, поэтому проблемы с двойным вызовом конструктора там нет.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,670
Записей в блоге: 30
10.02.2012, 14:00
Цитата Сообщение от AzaKendler Посмотреть сообщение
и если кровь из носа надо очистить память на которую ссылаются члены класса то вызов деструктора в том месте сделает это
Если вопрос стоит как кровь из носа, то вместо использования объекта использовать динамическое выделение памяти. И искусственно в это место засовывать placement new вовсе не к чему. Говоря про удобство и неудобство я имел в виду работу именно с ПЕРЕМЕННЫМИ типа класса, для которых компилятор АВТОМАТИЧЕСКИ вызывает конструкторы и деструкторы. Т.е. у тебя нет никакой возможности забыть вызвать деструктор

А проблема в общем случае не в том, чтобы освободить память, занимаемую экземпляром класса (как ты приводил в сових примерах). Экземпляр класса std::string занимает совсем немного места. Проблема в том, что экземпляр класса в момент создания внутри себя заводит динамически выделяемую память, которую можно освободить только удалив экземпляр класса.

Т.е. на Си я могу написать код:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct String str;
...
 
/* Как бы вызов конструктора, который я могу вставлять там, где мне заблагорассудится */
InitString (&str);
 
/* Поработали с экземпляром */
 
/* Как бы вызов деструктора, который я также могу вставлять там, где мне заблагорассудится */
ClearString (&str);
 
/* И могу даже повторно вызвать как бы конструктор (ибо захотелось мне повторно
 * проинициализировать существующий объект) */
InitString (&str);
На Си++ это выразить никак нельзя. Потому что конструктор может вызываться только автоматически и только при создании переменной. Аналогично деструктор. Единственное, что можно сделать в Си++ - так это вместо объектов использовать указатели и рожать-удалять объекты через new/delete, что, вобщем-то, совсем неэффективно. Понятно, что ровно такой код с вызовами функций можно написать и на Си++, но это уже как бы не есть программирование на Си++
0
 Аватар для AzaKendler
214 / 116 / 14
Регистрация: 30.05.2011
Сообщений: 1,772
Записей в блоге: 15
10.02.2012, 14:07
silent_1991, там вообще проблем нет. мы рассматриваем можно не можно.

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

конструктор с++ позволяет вызвать явно если это необходимо. explicit.

Добавлено через 4 минуты
Цитата Сообщение от Evg Посмотреть сообщение
Говоря про удобство и неудобство я имел в виду работу именно с ПЕРЕМЕННЫМИ типа класса, для которых компилятор АВТОМАТИЧЕСКИ вызывает конструкторы и деструкторы. Т.е. у тебя нет никакой возможности забыть вызвать деструктор
понятно. мне кажется в стринге в деструкторе как раз таки присутсвует код очищающий память динамического буфера и обнуляющий указатель. я это имел ввиду когда шла речь о стринге и о том, что требуется как то очистить его не используя { }.

Добавлено через 1 минуту
Цитата Сообщение от Evg Посмотреть сообщение
Но теперь
* // деструктор вызовется только в конце процедуры, а потребляемая string'ом память
* // всё это время будет висеть мёртвым грузом.
вот если от этого надо избавится, то можно использовать неудобное средство - вызвать деструктор. динамический буфер будет уничтожен. память таки осовбодится. другое дело что последующая попытка использования очищенного стринга может привести к ошибке. но ведь не об этом шла речь.
это наверно какой то случай мегаэкономии памяти должен быть, тогда лучше стринг наверно не использовать там
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.02.2012, 14:07

Задавать свойство лучше в 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 минуту Всем привет. Примитивнейшая задача: два класса обмениваются значениями переменных. Два объекта,...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru