Здравствуйте Lozovoy, вы писали:
L>Подскажите плз.Как создать динамический массив ?
L>Заранее спасибо.
Если тебе нужен ИМЕННО массив (а он тебе не нужен, почему —
читай ниже) — то вот так:
int sar[1979];//это такой грустный массив на стеке ...
//если он глобальный - то еще хуже ...
//хотя вряд-ли он глобальный ...
//ибо если он был бы глобальным - я бы назвал его
//g_ar ...
//я несколько отвлекся =) int *par = new int[1979];//выделяем динамически память под массив
par[1] = 1;//делаем вид что работает с массивом ...
par[9] = 2;//хотя par - это указатель - но вроде как сам кастится
par[7] = 7;//к типу массива ... ну да ладно
par[9] = 9;//delete[] par;//освобождаем память ... куда нам столько ее ...
par = new int[9];//выделяем динамически память под массив поменьше ...
par[1] = 1;//делаем вид что работает с массивом ...
par[9] = 2;//вот тут выход за пределы массива ... но в дебаге наверняка будет работать ...
par[7] = 7;//
par[9] = 9;//вот тут выход за пределы массива ... но в дебаге наверняка будет работать ...
//делаем еще миллион интересных вещей с этим массивом ...
//delete[] par;//забываем освобождить память delete par;//делаем ошибку ... (надо было delete[] par)...
Все вот так сложно ... но слава б#гу можно STL предоставляет нам
класс-контейнер vector .... с ним код гораздо проще:
#include <vector>//да - приходится подключать заголовочный файл ...using std::vector;//а кому щас легко ?
vector<int> vi(1979);
vi[1] = 1;
vi[9] = 2;
vi[7] = 7;
vi[9] = 9;
vi.resize(9);//уменьшаем размер вектора ...
vi[1] = 1;
vi[9] = 2;//вот тут выход за пределы вектора ... но в дебаге наверняка будет работать ...
vi[7] = 7;
vi[9] = 9;//вот тут выход за пределы вектора ... но в дебаге наверняка будет работать ...
//и все ... память сама освободиться и вычистится десткуртором славного класса vector ...
Здравствуйте Lozovoy, вы писали:
L>Подскажите плз.Как создать динамический массив ?
L>Заранее спасибо.
1.----------------
Есть ещё один способ, не перечисленный выше — это конструкция из malloc/realloc/free, например:
struct TMyStruct
{
int ID;
int Number;
};
TMyStruct* Array=0;
int ArraySize=5;
//создаём массив структур
//malloc выделит необходимое количество динамической памяти, надо помнить что она не инициализирует её!!
Array=(TMyStruct*)malloc(sizeof(TMyStruct)*ArraySize);
//обращение к массиву
Array[0]=Array[2];
Array[3].ID=7;
//изменения размера массива
//при этом, все данные в массиве сохраняются (т.е. первые пять элементов останутся не изменными)
ArraySize=20;
Array=(TMyStruct*)realloc(Array, sizeof(TMyStruct)*ArraySize);
//какие то операции с массивом
//удаление массива
free(Array);
2.------------------
//вот в принципе и всё, хотя функцией realloc можно заменить функции free и malloc, выглядит это так (пример 2):
Здравствуйте Igor Soukhov, вы писали:
IS>Здравствуйте Lozovoy, вы писали:
IS>//delete[] par;//забываем освобождить память IS>delete par;//делаем ошибку ... (надо было delete[] par)...
Мне казалось, что это не ошибка. По крайней мере все работает, утечек памяти не возникает. И вроде бы я даже где-то читал, что можно не указывать эти скобки после delete, хотя этой книги сейчас под рукой нет и проверить не могу.
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Здравствуйте Tigor, вы писали:
T>Здравствуйте Igor Soukhov, вы писали:
IS>>//delete[] par;//забываем освобождить память IS>>delete par;//делаем ошибку ... (надо было delete[] par)...
T>Мне казалось, что это не ошибка. По крайней мере все работает, утечек памяти не возникает. И вроде бы я даже где-то читал, что можно не указывать эти скобки после delete, хотя этой книги сейчас под рукой нет и проверить не могу.
А книга-то хорошая ? Ну там твердая обложка, большой шрифт, хорошая бумага ?
Здравствуйте Igor Soukhov, вы писали:
IS>А книга-то хорошая ? Ну там твердая обложка, большой шрифт, хорошая бумага ?
Да вроде хорошая :) Я потом в другой прочел, что надо эти скобки ставить и очень испугался, что все жизнь делал не правильно. :-)
Даже пререпатчил какой-то проектик свой.... А потом опять нашел ту книгу (Беризины — авторы вроде) и там точно было написано, что можно не указывать...
Visual C++ 6.0 не замечает утечек памяти, если их не указывать, поэтому я решил, что все нормально и они не обязательны.
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Здравствуйте Alex, вы писали:
A>На самом деле можно указывать, а можно и не указывать. A>Компилятор же тоже не глупый, он же видит что скрывается под именем переменной.
void f(int *n)
{
delete n; // и как ему тут понять, что там скрывается?
}
void f2()
{
int *n1 = new int;
int *n2 = new int[10];
f(n1);
f(n2);
}
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте IT, вы писали:
IT>Здравствуйте Alex, вы писали:
A>>На самом деле можно указывать, а можно и не указывать. A>>Компилятор же тоже не глупый, он же видит что скрывается под именем переменной.
IT>
IT>void f(int *n)
IT>{
IT> delete n; // и как ему тут понять, что там скрывается?
IT>}
IT>void f2()
IT>{
IT> int *n1 = new int;
IT> int *n2 = new int[10];
IT> f(n1);
IT> f(n2);
IT>}
IT>
В любом случае у нас есть массив, только n1 — указатель на массив из одного элемента, а n2 — указатель на массив из двух элементов. Вот и вся разница.
Здравствуйте Alex, вы писали:
A>На самом деле можно указывать, а можно и не указывать. A>Компилятор же тоже не глупый, он же видит что скрывается под именем переменной.
Ну так давайте тогда вообще выделять память через 'new[]', а освобождать через 'free()'. Компилятор же тоже не глупый...
Best regards,
Андрей Тарасевич,
Brainbench C and C++ Programming MVP
Здравствуйте Alex, вы писали:
A>>>На самом деле можно указывать, а можно и не указывать. A>>>Компилятор же тоже не глупый, он же видит что скрывается под именем переменной.
IT>>
IT>>void f(int *n)
IT>>{
IT>> delete n; // и как ему тут понять, что там скрывается?
IT>>}
IT>>void f2()
IT>>{
IT>> int *n1 = new int;
IT>> int *n2 = new int[10];
IT>> f(n1);
IT>> f(n2);
IT>>}
IT>>
A>В любом случае у нас есть массив, только n1 — указатель на массив из одного элемента, а n2 — указатель на массив из двух элементов. Вот и вся разница.
Такие компиляторы — в сад. Выделять память для одного 'int' как для массива 'int[1]' — расточительно.
Best regards,
Андрей Тарасевич,
Brainbench C and C++ Programming MVP
Здравствуйте Tigor, вы писали:
T>Вот маленький тестовый код (Visual C++ 6.0):
T>class Test T>{ T> public: T> Test(void) T> { T> printf("Constructor\n"); T> }
T> ~Test(void) T> { T> printf("Destructor\n"); T> } T>};
T>int main(int argc, char* argv[]) T>{ T> Test* pTest = new Test[3];
T> delete pTest; // Ошибка!!!! Debug Assertion Failed T> // после вызова деструктора первого объекта
T> char* pChar = new char [3];
T> delete pChar; Никаких ошибок во время выполнения, T> хотя утечка памяти, наверно, возникает.
T> return 0; T>}
T>Как заставить вижуал показать утечку памяти? Если я убираю delete pChar, он все равно ее не пишет.
Для того, чтобы VC показывал утечку памяти, над сделать
#define new DEBUG_NEW
и линковаться с MFC.
В любом случае, с чего ты взял, что будет утечка памяти из-за 'delete' вместо 'delete[]' ? Скажу тебе по секрету, что в данном конкретном случае никакой утечки памяти не будет.
В С++ смешивание 'delete' с 'delete[]' приводит к неопределенному поведению. Утечка памяти — лишь пример того, что может произойти.
Best regards,
Андрей Тарасевич,
Brainbench C and C++ Programming MVP
Здравствуйте Alex, вы писали:
A>В любом случае у нас есть массив, только n1 — указатель на массив из одного элемента, а n2 — указатель на массив из двух элементов. Вот и вся разница.
Пример не удачный с интами, а если будут объекты, то приплыли.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте Андрей Тарасевич, вы писали:
A>>В любом случае у нас есть массив, только n1 — указатель на массив из одного элемента, а n2 — указатель на массив из двух элементов. Вот и вся разница.
АТ>Такие компиляторы — в сад. Выделять память для одного 'int' как для массива 'int[1]' — расточительно.
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>Как вижно, компилятор делает один и тот же код. Что и требовалось доказать.
Ну здрасьте. В С++ экспериментальные "доказательства" не принимаются. Мало ли что там твой компилятор нагенерировал.
АТ>Для того, чтобы VC показывал утечку памяти, над сделать
АТ>
АТ>#define new DEBUG_NEW
АТ>
АТ>и линковаться с MFC.
Спасибо. А без MFC никак, да?
АТ>В любом случае, с чего ты взял, что будет утечка памяти из-за 'delete' вместо 'delete[]' ? Скажу тебе по секрету, что в данном конкретном случае никакой утечки памяти не будет.
АТ>В С++ смешивание 'delete' с 'delete[]' приводит к неопределенному поведению. Утечка памяти — лишь пример того, что может произойти.
А почему будет неопеделенное поведение? В чем отличие между освобождением памяти из под объектов и из под, например, массива байт? Кроме вызова деструкторов, разумеется. Или из-за них все проблемы?
Или, короче говоря, зачем вообще понадобилось два варианта delete, если размер массива и размер элемента вообще никак не передаются этому оператору?
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Здравствуйте 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'. Сегодня они работают "аналогично", а завтра программа будет рушиться...
АТ>>и линковаться с 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[]'. Тем не менее это — детали реализации. Это не повод смешивать эти механизмы в программе даже для таких типов.
Здравствуйте Alex, вы писали:
A>Ну и в чём же тогда разница между этими строчками? :))
В том, что в одной используется механизм выделения памяти 'new/delete', а в другой — 'new[]/delete[]'. А то, что код одинаковый получился — ни о чем не говорит. У меня вот эти строчки тоже одинаковый код порождают:
bool f = true;
char c = 1;
но это же не значит, что 'bool' и 'char' — одно и то же.
Здравствуйте Андрей Тарасевич, вы писали:
АТ>"Аналогично" они работают потому, что в контексте данного компилятора выделение/освобождение памяти для 'int' и для 'int[1]' оказалось идентичным. Пропобуй для класс 'T' с нетривиальным деструктором сделать 'new T' и 'new T[1]' и посмотри, како там получится "аналогично".
АТ>В любом случае, это не повод смешивать 'new/delete' и 'new[]/delete[]' даже для 'int'. Сегодня они работают "аналогично", а завтра программа будет рушиться...
Да для классов delete (вместо delete[]), будет вызывать только деструктор первого экземпляра класса в массиве, здесь не поспоришь.
Здравствуйте Андрей Тарасевич, вы писали:
АТ>Размер массива обязательно должен передаваться 'delete[]'. Хотя бы для того, чтобы знать, сколько деструкторов вызвать. Одним из способов такой передачи является помещение этого размера в выделенный через 'new[]' блок памяти.
Что-то я не врубился в это... :(
"В выделенный через new блок памяти" означает что new сам запоминает кол-во элементов?
Ведь я же не должнен делать так?
<ccode>
T pT = new T [10];
delete T[10];
</ccode>
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Здравствуйте 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[]' в С++ приводит к неопределенному поведению
Здравствуйте 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;
то напечатается размер выделенного массива.
Все это, конечно, детали конкретной реализации и использовать их в С++ прграммах ни в коем случае нельзя.
Здравствуйте Андрей Тарасевич, вы писали:
АТ>то, при условии что тип 'T' имеет нетривиальный деструктор, памяти на самом деле выделяется не 'sizeof(T) * n', а больше — '4 + sizeof(T) * n'. Первые 4 байта используются для хранения кол-ва элементов, т.е. туда кладется значение 'n'. Остальные используются для хранения собственно массива. Следствием этого являеться то, что возвращенный 'new[]' указатель указывает не на начало выделенного блока, а не его 4-й байт (нумерация с 0).
АТ>Если ты в MSVC++ 6.0 сделаешь вот так
АТ>
АТ>cout << *((unsigned*) p - 1) << endl;
АТ>
АТ>то напечатается размер выделенного массива.
АТ>Все это, конечно, детали конкретной реализации и использовать их в С++ прграммах ни в коем случае нельзя.
Спасибо большое. Но очередной дурацкий вопрос :)
А что такое "нетривиальный диструктор"? Никогда не читал подобных названий в книгах, наверно, не те читал...
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Здравствуйте Tigor, вы писали:
T>А что такое "нетривиальный диструктор"? Никогда не читал подобных названий в книгах, наверно, не те читал...
Попросту говоря, тривиальный деструктор — это деструктор, который нечего не делает и который при этом неявно определен компилятором. Остальные деструкторы являются нетривиальными.
Например, у не-класс типов ('int', 'double' и т.п.) деструктора нет вообще.
У такого класса
class A
{
};
деструктор есть (он неявно определен компилятором) и этот деструктор тривиален.
У такого класса
class B
{
public:
~B() {}
};
деструктор нетривиален, т.к. он определен программистом (хоть он ничего и не делает).
У такого класса
class C
{
std::vector<int> v;
};
деструктор тоже нетривиален. Хоть этот деструктор и определен компилятором неявно, он выполняет конкретную работу — вызывает деструктор для поля 'v'.
Здравствуйте Андрей Тарасевич, вы писали:
АТ>Попросту говоря, тривиальный деструктор — это деструктор, который нечего не делает и который при этом неявно определен компилятором. Остальные деструкторы являются нетривиальными.
Большое спасибо и спокойной ночи :)
К сожалению, в действительности все выглядит иначе, чем на самом деле.
Здравствуйте VladD2, вы писали:
VD>Здается мне, что после оптимизации ни каких тривиальных деструкторов не останется. Слишком уж дорого деать пустые колы. Или я не проав?
Тривиальных деструкторов "не останется" в любом случае. Даже никакой оптимизации не надо. Попросту потому, что их на самом деле не существует :) Тривиальные деструкторы — это абстракция, которая существует только на уровне спецификации языка С++. Для единообразия, так сказать. Так что пустых call-ов не будет.
А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)
Здравствуйте Андрей Тарасевич, вы писали:
АТ>А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)
Ну, если определены в теле класса, должны выкидываться (они же inline) и при некоторый опциях (полезных) оптимизации тоже должны выкидываться.
А на счет абстракции... так похоже, что Вы (ты. Как лучше?) народ только запутал. :(
По крайней мере, со стороны так выглядит.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте Андрей Тарасевич, вы писали:
АТ>А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)
Точно. Компилятор просто не имеет права их выкинуть (ни какого). Откуда другому модулю известно — пустые они, не пустые... Боюсь, здесь и глобальная оптимизация не поможет... Ну разве что только ОЧЕНЬ глобальная. Кстати, это относится не только к деструкторам, которые практически ничем не отличается от других методов класса.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте Андрей Тарасевич, вы писали:
АТ>Здравствуйте Igor Soukhov, вы писали:
IS>>2Tigor, IT, Андрей, Влад !
IS>>Пришел на работу — глянул — сабж ! IS>>=)
АТ>Ночь — понятие относительное. У меня GMT -08:00 :)
я знаю =) вернее помню =) ... меня потряс размер треда ... 38 писем в ящике с утра
хотя там бывает ну ... 2-3 ... да и щас значит уже у тя ночь =)
Здравствуйте Igor Soukhov, вы писали:
IS>>>2Tigor, IT, Андрей, Влад !
IS>>>Пришел на работу — глянул — сабж ! IS>>>=)
АТ>>Ночь — понятие относительное. У меня GMT -08:00 :) IS>я знаю =) вернее помню =) ... меня потряс размер треда ... 38 писем в ящике с утра IS>хотя там бывает ну ... 2-3 ... да и щас значит уже у тя ночь =)
Это у нас вчера вторая смена заступила ;)
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте IT, вы писали:
IT>Здравствуйте Андрей Тарасевич, вы писали:
АТ>>А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)
IT>Точно. Компилятор просто не имеет права их выкинуть (ни какого). Откуда другому модулю известно — пустые они, не пустые... Боюсь, здесь и глобальная оптимизация не поможет... Ну разве что только ОЧЕНЬ глобальная. Кстати, это относится не только к деструкторам, которые практически ничем не отличается от других методов класса.
Ты чёё... мужик? Где ты видал шоб модули думали? ;o)
Если функция помечена как virtual или export/extern, то конечно ее выкинуть не должны, а если нет, то выкинут нафиг. :) Модульи то все вместе компилируются.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, вы писали:
АТ>>>А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)
IT>>Точно. Компилятор просто не имеет права их выкинуть (ни какого). Откуда другому модулю известно — пустые они, не пустые... Боюсь, здесь и глобальная оптимизация не поможет... Ну разве что только ОЧЕНЬ глобальная. Кстати, это относится не только к деструкторам, которые практически ничем не отличается от других методов класса.
VD>Если функция помечена как virtual или export/extern, то конечно ее выкинуть не должны, а если нет, то
Любая функция по умолчанию является 'extern'.
VD>выкинут нафиг. :) Модульи то все вместе компилируются.
Под модулями понимается как раз таки то, что компилируется отдельно. Например, DLL.
Здравствуйте Андрей Тарасевич, вы писали:
АТ>Любая функция по умолчанию является 'extern'.
Да?
И эта тоже?
class xxx
{
void f1() {};
};
ню-ню...
VD>>выкинут нафиг. :) Модульи то все вместе компилируются.
АТ>Под модулями понимается как раз таки то, что компилируется отдельно. Например, DLL.
Думаю IT под ними .obj пониал... когда писал.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, вы писали:
VD>>>выкинут нафиг. :) Модульи то все вместе компилируются.
АТ>>Под модулями понимается как раз таки то, что компилируется отдельно. Например, DLL.
VD>Думаю IT под ними .obj пони[b]м[/]ал... когда писал.
Процетирует ещё раз первоисточник: АТ>А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)
Ясный пень, компилятор (в классическом смысле этого слова) ничего никуда выкидывать не дожен, кроме одного случая, когда функция статическая (локальная в модуле) и нигде не вызывается. Удалять неиспользуемые функции — это работа линковщика, версия от MS которого как раз умеет делать своё дело очень не плохо.
А теперь обратимся к цитате. Речь идёт не о неиспользуемых модулях, а о тех, которые ничего не делают. Что бы линковщик их удалил, он должен во-первых понять, что в них пусто, а во-вторых изменить код вызывающей процедуры так, чтобы она ничего не вызывала. 8-/ Теперь объясните мне — как это можно сделать, хотя бы теоретически?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте IT, вы писали:
IT>Здравствуйте VladD2, вы писали:
VD>>>>выкинут нафиг. :) Модульи то все вместе компилируются.
АТ>>>Под модулями понимается как раз таки то, что компилируется отдельно. Например, DLL.
VD>>Думаю IT под ними .obj пони[b]м[/]ал... когда писал.
IT>Процетирует ещё раз первоисточник: АТ>>А вот пустрые деструкторы, явно определенные программистом, (по определению они нетривиальны) в MSVC++, например, оптимизатором не выкидываются. И да, получаются пустые call-ы. (Если они не inline, конечно.)
IT> IT>Ясный пень, компилятор (в классическом смысле этого слова) ничего никуда выкидывать не дожен, кроме одного случая, когда функция статическая (локальная в модуле) и нигде не вызывается. Удалять неиспользуемые функции — это работа линковщика, версия от MS которого как раз умеет делать своё дело очень не плохо. IT>А теперь обратимся к цитате. Речь идёт не о неиспользуемых модулях, а о тех, которые ничего не делают. Что бы линковщик их удалил, он должен во-первых понять, что в них пусто, а во-вторых изменить код вызывающей процедуры так, чтобы она ничего не вызывала. 8-/ Теперь объясните мне — как это можно сделать, хотя бы теоретически? IT>
Включить опцию пропогирующую :)) inline. И шоо любопытно ни одной пустой фукции не останется. Глобал Аптямязэйшооон... понимаш. ;)
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте VladD2, вы писали:
АТ>>Любая функция по умолчанию является 'extern'.
VD>Да?
VD>И эта тоже?
VD>class xxx VD>{ VD> void f1() {}; VD>};
VD>ню-ню...
Я имел в виду, что любая функция ро умолчанию имеет external linkage. Да, и эта тоже. Inline на linkage не влияет. Просто добавляется требование того, чтобы функция быда определена во всех единицах компиляции. Логика мне не совсем ясна (какая разница, какое linkage имеет функция, если ее все равно требуется определять во всех единицах компиляции), но так сказано в спецификации языка.
VD>>>выкинут нафиг. :) Модульи то все вместе компилируются.
АТ>>Под модулями понимается как раз таки то, что компилируется отдельно. Например, DLL.
VD>Думаю IT под ними .obj пониал... когда писал.
Думаю, что он все таки имел в виду EXE/DLL модули.
Здравствуйте Андрей Тарасевич, вы писали:
АТ>Я имел в виду, что любая функция ро умолчанию имеет external linkage. Да, и эта тоже. Inline на linkage не влияет. Просто добавляется требование того, чтобы функция быда определена во всех единицах компиляции. Логика мне не совсем ясна (какая разница, какое linkage имеет функция, если ее все равно требуется определять во всех единицах компиляции), но так сказано в спецификации языка.
Здесь как раз логика правильная, ты ведь можешь спокойно взять адрес этой функции ;)
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте IT, вы писали:
АТ>>Я имел в виду, что любая функция ро умолчанию имеет external linkage. Да, и эта тоже. Inline на linkage не влияет. Просто добавляется требование того, чтобы функция быда определена во всех единицах компиляции. Логика мне не совсем ясна (какая разница, какое linkage имеет функция, если ее все равно требуется определять во всех единицах компиляции), но так сказано в спецификации языка.
IT>Здесь как раз логика правильная, ты ведь можешь спокойно взять адрес этой функции ;)
Да, с этой точки зрения логика есть :) В одной из рабочих версий стандарта языка inline функциям по умолчанию предлагалось давать internal linkage. И для того, чтобы гарантировать совпадение адресов одной и той же inline функции в разных единицах компиляции нужно было бы писать 'extern inline'. Потом эту часть стандарта изменили и inline функции получили external linkage. Т.е. и без явного 'extern' адрес inline-функции везде должен получаться одинаковым. Хотя до сих по можно услышать утверждения, что для гарантрованного совпадения адресов требуется 'extern inline'. По-видимому существуют еще компиляторы, которые следуют устаревшей спецификации. Подозреваю, что MSVC++ 6.0 тоже к ним относится (лень проверять).