Re[8]: Динамический массив???
От: Андрей Тарасевич Беларусь  
Дата: 25.09.01 20:21
Оценка:
Здравствуйте Alex, вы писали:


A>1.--------------------------------------------

A>//C++

A> int* p1=new int;


A>//то же на ассемблере


A> push 4

A> call @$bnew$qui
A> pop ecx
A> mov dword ptr [ebp-12],eax

A>2.--------------------------------------------

A>//C++
A> int* p2=new int[1];

A>//то же на ассемблере

A> push 4
A> call @$bnwa$qui
A> pop ecx
A> mov dword ptr [ebp-16],eax


A>Как вижно, компилятор делает один и тот же код. Что и требовалось доказать.


Ну здрасьте. В С++ экспериментальные "доказательства" не принимаются. Мало ли что там твой компилятор нагенерировал.
Best regards,
Андрей Тарасевич
Re[8]: Динамический массив???
От: Tigor Россия  
Дата: 25.09.01 20:23
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:


АТ>Для того, чтобы VC показывал утечку памяти, над сделать


АТ>
АТ>#define new DEBUG_NEW
АТ>


АТ>и линковаться с MFC.


Спасибо. А без MFC никак, да?

АТ>В любом случае, с чего ты взял, что будет утечка памяти из-за 'delete' вместо 'delete[]' ? Скажу тебе по секрету, что в данном конкретном случае никакой утечки памяти не будет.


АТ>В С++ смешивание 'delete' с 'delete[]' приводит к неопределенному поведению. Утечка памяти — лишь пример того, что может произойти.


А почему будет неопеделенное поведение? В чем отличие между освобождением памяти из под объектов и из под, например, массива байт? Кроме вызова деструкторов, разумеется. Или из-за них все проблемы?

Или, короче говоря, зачем вообще понадобилось два варианта delete, если размер массива и размер элемента вообще никак не передаются этому оператору?
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Re[8]: Динамический массив???
От: Андрей Тарасевич Беларусь  
Дата: 25.09.01 20:26
Оценка:
Здравствуйте Alex, вы писали:

A>>>В любом случае у нас есть массив, только n1 — указатель на массив из одного элемента, а n2 — указатель на массив из двух элементов. Вот и вся разница.


АТ>>Такие компиляторы — в сад. Выделять память для одного 'int' как для массива 'int[1]' — расточительно.


A>Эти две строки:


A>int *n1 = new int;

A>int *n1 = new int[1];

A>работают аналогично


"Аналогично" они работают потому, что в контексте данного компилятора выделение/освобождение памяти для 'int' и для 'int[1]' оказалось идентичным. Пропобуй для класс 'T' с нетривиальным деструктором сделать 'new T' и 'new T[1]' и посмотри, како там получится "аналогично".

В любом случае, это не повод смешивать 'new/delete' и 'new[]/delete[]' даже для 'int'. Сегодня они работают "аналогично", а завтра программа будет рушиться...
Best regards,
Андрей Тарасевич
Re[9]: Динамический массив???
От: Alex  
Дата: 25.09.01 20:34
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

Ну и в чём же тогда разница между этими строчками? :))
Re[9]: Динамический массив???
От: Андрей Тарасевич Беларусь  
Дата: 25.09.01 20:38
Оценка:
Здравствуйте Tigor, вы писали:

АТ>>
АТ>>#define new DEBUG_NEW
АТ>>


АТ>>и линковаться с MFC.


T>Спасибо. А без MFC никак, да?


Именно тот рапорт утечек памяти в Output Window, который привыкли видеть пользователи MSVC++, делается MFC. Есть и другие средства: NuMega BoundsChecker, Rational Purify.

АТ>>В любом случае, с чего ты взял, что будет утечка памяти из-за 'delete' вместо 'delete[]' ? Скажу тебе по секрету, что в данном конкретном случае никакой утечки памяти не будет.


АТ>>В С++ смешивание 'delete' с 'delete[]' приводит к неопределенному поведению. Утечка памяти — лишь пример того, что может произойти.


T>А почему будет неопеделенное поведение? В чем отличие между освобождением памяти из под объектов и из под, например, массива байт? Кроме вызова деструкторов, разумеется. Или из-за них все проблемы?


В С++ 'new/delete' и 'new[]/delete[]' — два абсолютно независимых мезанизма распределения памяти. Они могут быть похожи, а могут вообще не иметь ничего общего. Поэтому их и нельзя смешивать.

T>Или, короче говоря, зачем вообще понадобилось два варианта delete, если размер массива и размер элемента вообще никак не передаются этому оператору?


Размер массива обязательно должен передаваться 'delete[]'. Хотя бы для того, чтобы знать, сколько деструкторов вызвать. Одним из способов такой передачи является помещение этого размера в выделенный через 'new[]' блок памяти. Если для некоторого типа 'T' компилятор не интересует размер массива в 'delete[]', то для этого типа 'T' компилятор имеет право использовать один и тот же механизм и в 'new/delete' и в 'new[]/delete[]'. Тем не менее это — детали реализации. Это не повод смешивать эти механизмы в программе даже для таких типов.
Best regards,
Андрей Тарасевич
Re[10]: Динамический массив???
От: Андрей Тарасевич Беларусь  
Дата: 25.09.01 20:44
Оценка:
Здравствуйте Alex, вы писали:

A>Ну и в чём же тогда разница между этими строчками? :))


В том, что в одной используется механизм выделения памяти 'new/delete', а в другой — 'new[]/delete[]'. А то, что код одинаковый получился — ни о чем не говорит. У меня вот эти строчки тоже одинаковый код порождают:

bool f = true;
char c = 1;


но это же не значит, что 'bool' и 'char' — одно и то же.
Best regards,
Андрей Тарасевич
Re[9]: Динамический массив???
От: Alex  
Дата: 25.09.01 20:55
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

АТ>"Аналогично" они работают потому, что в контексте данного компилятора выделение/освобождение памяти для 'int' и для 'int[1]' оказалось идентичным. Пропобуй для класс 'T' с нетривиальным деструктором сделать 'new T' и 'new T[1]' и посмотри, како там получится "аналогично".


АТ>В любом случае, это не повод смешивать 'new/delete' и 'new[]/delete[]' даже для 'int'. Сегодня они работают "аналогично", а завтра программа будет рушиться...


Да для классов delete (вместо delete[]), будет вызывать только деструктор первого экземпляра класса в массиве, здесь не поспоришь.
Re[10]: Динамический массив???
От: Tigor Россия  
Дата: 25.09.01 20:59
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

АТ>Размер массива обязательно должен передаваться 'delete[]'. Хотя бы для того, чтобы знать, сколько деструкторов вызвать. Одним из способов такой передачи является помещение этого размера в выделенный через 'new[]' блок памяти.


Что-то я не врубился в это... :(
"В выделенный через new блок памяти" означает что new сам запоминает кол-во элементов?

Ведь я же не должнен делать так?
<ccode>
T pT = new T [10];

delete T[10];
</ccode>
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Re[10]: Динамический массив???
От: Андрей Тарасевич Беларусь  
Дата: 25.09.01 21:02
Оценка:
Здравствуйте Alex, вы писали:

АТ>>"Аналогично" они работают потому, что в контексте данного компилятора выделение/освобождение памяти для 'int' и для 'int[1]' оказалось идентичным. Пропобуй для класс 'T' с нетривиальным деструктором сделать 'new T' и 'new T[1]' и посмотри, како там получится "аналогично".


АТ>>В любом случае, это не повод смешивать 'new/delete' и 'new[]/delete[]' даже для 'int'. Сегодня они работают "аналогично", а завтра программа будет рушиться...


A>Да для классов delete (вместо delete[]), будет вызывать только деструктор первого экземпляра класса в массиве, здесь не поспоришь.


Утверждение, справедливое для MSVC++ 6.0. Может быть еще для каких-то компиляторов. Но не более. В общем случае — С++ — такого утверждать никто не может. Смешивание 'new/delete' и 'new[]/delete[]' в С++ приводит к неопределенному поведению
Best regards,
Андрей Тарасевич
Re[11]: Динамический массив???
От: Андрей Тарасевич Беларусь  
Дата: 25.09.01 21:14
Оценка:
Здравствуйте Tigor, вы писали:

T>Здравствуйте Андрей Тарасевич, вы писали:


АТ>>Размер массива обязательно должен передаваться 'delete[]'. Хотя бы для того, чтобы знать, сколько деструкторов вызвать. Одним из способов такой передачи является помещение этого размера в выделенный через 'new[]' блок памяти.


T>Что-то я не врубился в это... :(

T>"В выделенный через new блок памяти" означает что new сам запоминает кол-во элементов?

Да, именно так. 'new[]' должен сам записывать куда-то кол-во выделенных элементов.

В частности, в MSVC++ 6.0, если ты выделяешь массив из 'n' элеметнов типа 'T'

T* p = new T[n];


то, при условии что тип 'T' имеет нетривиальный деструктор, памяти на самом деле выделяется не 'sizeof(T) * n', а больше — '4 + sizeof(T) * n'. Первые 4 байта используются для хранения кол-ва элементов, т.е. туда кладется значение 'n'. Остальные используются для хранения собственно массива. Следствием этого являеться то, что возвращенный 'new[]' указатель указывает не на начало выделенного блока, а не его 4-й байт (нумерация с 0).

Если ты в MSVC++ 6.0 сделаешь вот так

cout << *((unsigned*) p - 1) << endl;


то напечатается размер выделенного массива.

Все это, конечно, детали конкретной реализации и использовать их в С++ прграммах ни в коем случае нельзя.
Best regards,
Андрей Тарасевич
Re[12]: Динамический массив???
От: Tigor Россия  
Дата: 25.09.01 21:22
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

АТ>то, при условии что тип 'T' имеет нетривиальный деструктор, памяти на самом деле выделяется не 'sizeof(T) * n', а больше — '4 + sizeof(T) * n'. Первые 4 байта используются для хранения кол-ва элементов, т.е. туда кладется значение 'n'. Остальные используются для хранения собственно массива. Следствием этого являеться то, что возвращенный 'new[]' указатель указывает не на начало выделенного блока, а не его 4-й байт (нумерация с 0).


АТ>Если ты в MSVC++ 6.0 сделаешь вот так


АТ>
АТ>cout << *((unsigned*) p - 1) << endl;
АТ>


АТ>то напечатается размер выделенного массива.


АТ>Все это, конечно, детали конкретной реализации и использовать их в С++ прграммах ни в коем случае нельзя.


Спасибо большое. Но очередной дурацкий вопрос :)
А что такое "нетривиальный диструктор"? Никогда не читал подобных названий в книгах, наверно, не те читал...
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Re[12]: Динамический массив???
От: Alex  
Дата: 25.09.01 21:29
Оценка:
Здравствуйте Андрей Тарасевич:

Кстати, а что будет если у конструктора будут входные параметры?
Re[13]: Динамический массив???
От: Андрей Тарасевич Беларусь  
Дата: 25.09.01 21:40
Оценка:
Здравствуйте Tigor, вы писали:

T>А что такое "нетривиальный диструктор"? Никогда не читал подобных названий в книгах, наверно, не те читал...


Попросту говоря, тривиальный деструктор — это деструктор, который нечего не делает и который при этом неявно определен компилятором. Остальные деструкторы являются нетривиальными.

Например, у не-класс типов ('int', 'double' и т.п.) деструктора нет вообще.

У такого класса

class A
{
};


деструктор есть (он неявно определен компилятором) и этот деструктор тривиален.

У такого класса

class B
{
public:
  ~B() {}
};


деструктор нетривиален, т.к. он определен программистом (хоть он ничего и не делает).

У такого класса

class C
{
  std::vector<int> v;
};


деструктор тоже нетривиален. Хоть этот деструктор и определен компилятором неявно, он выполняет конкретную работу — вызывает деструктор для поля 'v'.
Best regards,
Андрей Тарасевич
Re[14]: Динамический массив???
От: Tigor Россия  
Дата: 25.09.01 21:45
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

АТ>Попросту говоря, тривиальный деструктор — это деструктор, который нечего не делает и который при этом неявно определен компилятором. Остальные деструкторы являются нетривиальными.


Большое спасибо и спокойной ночи :)
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Re[13]: Динамический массив???
От: Андрей Тарасевич Беларусь  
Дата: 25.09.01 21:47
Оценка:
Здравствуйте Alex, вы писали:

A>Здравствуйте Андрей Тарасевич:


A>Кстати, а что будет если у конструктора будут входные параметры?


Если у класса нет конструктора по умолчанию, то выделить массив элементов этого класса при помощи 'new[]' невозможно.
Best regards,
Андрей Тарасевич
Re[14]: Динамический массив???
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.09.01 21:55
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

Здается мне, что после оптимизации ни каких тривиальных деструкторов не останется. Слишком уж дорого деать пустые колы. Или я не проав?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Динамический массив???
От: Андрей Тарасевич Беларусь  
Дата: 25.09.01 22:06
Оценка:
Здравствуйте VladD2, вы писали:

VD>Здается мне, что после оптимизации ни каких тривиальных деструкторов не останется. Слишком уж дорого деать пустые колы. Или я не проав?


Тривиальных деструкторов "не останется" в любом случае. Даже никакой оптимизации не надо. Попросту потому, что их на самом деле не существует :) Тривиальные деструкторы — это абстракция, которая существует только на уровне спецификации языка С++. Для единообразия, так сказать. Так что пустых call-ов не будет.

А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)
Best regards,
Андрей Тарасевич
Re[16]: Динамический массив???
От: VladD2 Российская Империя www.nemerle.org
Дата: 25.09.01 22:24
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

АТ>А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)


Ну, если определены в теле класса, должны выкидываться (они же inline) и при некоторый опциях (полезных) оптимизации тоже должны выкидываться.

А на счет абстракции... так похоже, что Вы (ты. Как лучше?) народ только запутал. :(
По крайней мере, со стороны так выглядит.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: Динамический массив???
От: IT Россия linq2db.com
Дата: 26.09.01 02:14
Оценка:
Здравствуйте Андрей Тарасевич, вы писали:

АТ>А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)


Точно. Компилятор просто не имеет права их выкинуть (ни какого). Откуда другому модулю известно — пустые они, не пустые... Боюсь, здесь и глобальная оптимизация не поможет... Ну разве что только ОЧЕНЬ глобальная. Кстати, это относится не только к деструкторам, которые практически ничем не отличается от других методов класса.
Если нам не помогут, то мы тоже никого не пощадим.
Re[17]: мужики - вы че по ночам творите !
От: Igor Soukhov  
Дата: 26.09.01 05:26
Оценка:
2Tigor, IT, Андрей, Влад !

Пришел на работу — глянул — сабж !
=)
* thriving in a production environment *
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.