malloc vs new []
От: DemAS http://demas.me
Дата: 24.01.08 10:08
Оценка: -1
Добрый день.

Правильно ли я понимаю, что:

1. new char[1000] — гарантирует, что выделенная память будет представлять собой непрерывный фрагмент
2. malloc() — не гарантирует, что выделенная память будет представлять собой непрерывный фрагмент
3. если у меня память выделена с помощью new [], то я могу обращаться к отдельным ее байтам по индексу:
    unsigned char* b = new unsigned char[cnt];
    for(int i = 0; i < cnt2; i++)
       b[i] = s->storage[i];

4. Если память получена в результате вызова malloc, то обращаться к отдельным ее байтам по индексу я не могу (вследствии 2).

?
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re: malloc vs new []
От: runtime2  
Дата: 24.01.08 10:19
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS>Добрый день.


DAS> Правильно ли я понимаю, что:


DAS> 2. malloc() — не гарантирует, что выделенная память будет представлять собой непрерывный фрагмент


Никогда такого не слышал
Скорее всего не верно.
Re[2]: malloc vs new []
От: DemAS http://demas.me
Дата: 24.01.08 10:28
Оценка:
Здравствуйте, runtime2, Вы писали:

R>Никогда такого не слышал

R>Скорее всего не верно.

Хм.. а чем тогда отличается malloc() от new ?
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re: malloc vs new []
От: De Bug Финляндия  
Дата: 24.01.08 10:37
Оценка: 2 (1)
Здравствуйте, DemAS, Вы писали:

DAS> Правильно ли я понимаю, что:


DAS> 2. malloc() — не гарантирует, что выделенная память будет представлять собой непрерывный фрагмент

Это утверждение неверно, malloc тоже выделит непрерывный фрагмент.
malloc и new различаются реакцией на исчерпание памяти и тем, что malloc ничего не знает про конструкторы.
Re[2]: malloc vs new []
От: DemAS http://demas.me
Дата: 24.01.08 10:39
Оценка:
Здравствуйте, De Bug, Вы писали:

DB>malloc и new различаются реакцией на исчерпание памяти и тем, что malloc ничего не знает про конструкторы.


Спасибо. Первое понял. Второе — поищу
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re: malloc vs new []
От: superman  
Дата: 24.01.08 10:56
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS>Добрый день.


DAS> Правильно ли я понимаю, что:


DAS> 1. new char[1000] — гарантирует, что выделенная память будет представлять собой непрерывный фрагмент

DAS> 2. malloc() — не гарантирует, что выделенная память будет представлять собой непрерывный фрагмент
DAS> 3. если у меня память выделена с помощью new [], то я могу обращаться к отдельным ее байтам по индексу:
DAS>
DAS>    unsigned char* b = new unsigned char[cnt];
DAS>    for(int i = 0; i < cnt2; i++)
DAS>       b[i] = s->storage[i]; 
DAS>

DAS> 4. Если память получена в результате вызова malloc, то обращаться к отдельным ее байтам по индексу я не могу (вследствии 2).

DAS> ?


нет, вы понимаете неправвильно. И откуда вообще эти глупости про malloc и не непрерывные куски?
Re[3]: malloc vs new []
От: elmal  
Дата: 24.01.08 11:08
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS> Хм.. а чем тогда отличается malloc() от new ?

Грубо говоря — malloc это Си, new — это C++ . На С++ про malloc, calloc, realloc и free лучше забыть, new рулит .
Re[2]: malloc vs new []
От: DemAS http://demas.me
Дата: 24.01.08 11:11
Оценка:
Здравствуйте, superman, Вы писали:

S>нет, вы понимаете неправвильно. И откуда вообще эти глупости про malloc и не непрерывные куски?


Да, прошу прощения. Подвел мой английский — неправильно понял фразу.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[3]: malloc vs new []
От: superman  
Дата: 24.01.08 11:21
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS> Да, прошу прощения. Подвел мой английский — неправильно понял фразу.


да ладно уж, С++ простит
Re: malloc vs new []
От: dorofeevilya Россия  
Дата: 24.01.08 13:02
Оценка: 4 (1)
Здравствуйте, DemAS, Вы писали:

DAS>Добрый день.


DAS> Правильно ли я понимаю, что:


DAS> 1. new char[1000] — гарантирует, что выделенная память будет представлять собой непрерывный фрагмент

DAS> 2. malloc() — не гарантирует, что выделенная память будет представлять собой непрерывный фрагмент
DAS> 3. если у меня память выделена с помощью new [], то я могу обращаться к отдельным ее байтам по индексу:
DAS>
DAS>    unsigned char* b = new unsigned char[cnt];
DAS>    for(int i = 0; i < cnt2; i++)
DAS>       b[i] = s->storage[i]; 
DAS>

DAS> 4. Если память получена в результате вызова malloc, то обращаться к отдельным ее байтам по индексу я не могу (вследствии 2).

DAS> ?


Дело в том, что оператор new, если Вы посмотрите в debugger'е, в результате (после некоторых танцев с бубном) для выделения памяти все равно вызовет все тот же malloc() (дебажную версию, что-то типа _dbg_malloc()), которая в свою очередь вызовет (в случае винды) API-шную HeapAlloc(). То есть, по сути, new и malloc() — одно и то же. Разница лишь в том, что new выделяет еще небольшой кусок памяти (см. про танцы ) для записи туда некоторой мета-инфы, чтобы в дальнейшем контролировать утечки памяти, ну или что-то в этом роде.
Re[3]: malloc vs new []
От: LaptevVV Россия  
Дата: 24.01.08 13:21
Оценка: 4 (1)
Здравствуйте, DemAS, Вы писали:

DAS> Хм.. а чем тогда отличается malloc() от new ?

Как пишет Герб Саттер — это просто две большие разницы. Не смешивайте их никогда.
New может быть реализована с помощью malloc(), а наоборот — нет.
malloc(0 просто выделяет память, а при использовании new для неPOD типов вызывается конструктор.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: malloc vs new []
От: dorofeevilya Россия  
Дата: 24.01.08 13:30
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, DemAS, Вы писали:


DAS>> Хм.. а чем тогда отличается malloc() от new ?

LVV>Как пишет Герб Саттер — это просто две большие разницы. Не смешивайте их никогда.
LVV>New может быть реализована с помощью malloc(), а наоборот — нет.
LVV>malloc(0 просто выделяет память, а при использовании new для неPOD типов вызывается конструктор.

Простите, я не в курсе, что значит неPOD тип? Первый раз слышу
malloc vs new []
От: LaptevVV Россия  
Дата: 24.01.08 13:34
Оценка: 2 (1) -1
#Имя: FAQ.cpp.mallocvsnew
Здравствуйте, DemAS, Вы писали:

DAS> Спасибо. Первое понял. Второе — поищу

Искать не нужно — смотри сюды

Было бы просто здорово, если бы программист мог писать программы, совсем не заботясь о памяти. Более того, в идеале программист и не должен ничего знать о том, где размещаются переменные программы. Но, к сожалению (или к счастью), мы живем в реальном мире и работаем на реальных компьютерах, которые имеют ограниченную память. И хотя некоторые языки программирования пытаются скрыть от программиста факт наличия памяти, имитируя неограниченный ее объем, на практике обычно оказывается, что не учитывать конечность памяти просто нельзя — это плохо сказывается на «здоровье» программы.
С++ в этом смысле «поступает» значительно «честнее»: уже на 4-й странице стандарта описывается «модель памяти С++» [1-1.7]. Согласно этой модели, основной единицей памяти в С++ является байт. Память, доступная программе, состоит из последовательности байт. Каждый байт имеет уникальный адрес и состоит из последовательности бит. Однако стандарт не утверждает, что байт обязательно содержит 8 бит — напротив, количество бит в байте является особенностью реализации. Тем не менее, одно требование к байту прописано явно: байт должен быть такого размера, чтобы в нем был способен поместиться любой символ из базового набора символов.
Соответственно, операция sizeof()[1-5.3.3] выдает размер объекта или типа в байтах, а результат выполнения sizeof(char), sizeof(signed char), sizeof(unsigned char) равен 1. Размеры остальных встроенных типов зависят от реализации.
Память и объекты
Каждый объект С++ является «областью памяти» [1-1.8]. Объект обладает рядом свойств, например, имеет имя и тип. Объекту приписывается «период хранения» (в памяти — storage duration) [1-3.7]. Это свойство и определяет время жизни объекта [1-3.8]. Различается три периода хранения и в соответствии с этим — три класса памяти, в которых размещаются объекты:
 статическая память;
 автоматическая память;
 динамическая память;
В статической памяти размещаются все глобальные объекты, объявленные вне каких-либо функций и классов, а также любые статически переменные, в том числе и объявленные в функциях, и в классах. Память для этих объектов выделяется в момент запуска программы, а уничтожаются такие объекты только при завершении программы.
В автоматической памяти размещаются локальные не статические объекты, которые объявляются в любом блоке, в том числе в теле любой функции. В частности, переменные, объявленные в теле главной функции, тоже являются локальными. Память таким объектам выделяется в момент объявления, а уничтожаются такие объекты в конце области видимости. Естественно, наиболее подходящей реализацией является размещение локальных объектов в стековой памяти (хотя в стандарте об этом нет ни слова).
Свободная память и куча
Динамическая память выделяется объектам во время выполнения программы с помощью специальных операций new и new[][1-5.3.4]. Возврат динамической памяти (и уничтожение объектов при этом) тоже выполняются специальными операциями delete и delete[] [1-5.3.5]. В стандарте [1-12.5] такая динамическая память называется «свободной» памятью — мы ниже рассмотрим подробности работы с ней.
Однако С++ включает и другой вид динамической памяти, о котором в стандарте явно не сказано. Дело в том, что в С++ по наследству от С остались функции malloc(), calloc(), realloc() и free() [1-20.4.6], которые тоже работают с динамической памятью. Первые три из них различными способами выделяют динамическую память, а последняя, естественно, освобождает. Герб Саттер [21] называет динамическую память, с которой работают функции malloc()/free() кучей, как она и называется в стандарте С99 [59].
Стандарт С++ не определяет, должны ли быть реализованы операции new/delete с помощью этих функций. Однако в стандарте явно говорится [1-20.4.6/3/4], что функции malloc()/free() не должны быть реализованы с помощью операций new/delete. Поэтому в общем случае свободная память, с которой работают операции new/delete, и динамическая память, с которой работают функции malloc()/free(), — это «две большие разницы». Возможно, в каком-нибудь компиляторе эти два вида динамической памяти и совпадают, но полагаться на это ни в коем случае нельзя.
Отсюда следует совершенно однозначный вывод: никогда не «смешивайте» эти два механизма управления динамической памятью в своих программах. Этот совет достоин того, чтобы повторить его еще раз!

СОВЕТ
Никогда не «смешивайте» два механизма управления динамической памятью в своих программах.

Память, выделенная одной из операций new, должна возвращаться системе только соответствующей операцией delete, а память, выделенная одной из функций malloc(), calloc(), или realloc(), должна возвращаться только с помощью функции free().
Управление свободной памятью
Основная проблема, связанная с функциями malloc()/free(), заключается в том, что эти функции ничего «не знают» о конструкторах и деструкторах. В связи с этим возникают трудности с размещением объектов в этой памяти и их инициализацией. Простой пример показывает это (листинг 8.2).

//Листинг 8.2. Проблемы инициализации при использовании malloc()/free()
#include <cstdlib>                    // malloc()/free()
#include <cstring>                    // memset()
#include <iostream>            
using namespace std;
class Object
{   double a;
    int b;
    enum  { size = 100 };
    int buf[size];
   public:
    void Init()
    {  double a = 0.0; b = -1;
       memset(buf, 0, size);
    }
};
int main()
{   Object *p = (Object *)malloc(sizeof(Object));    // выделение памяти
    if (!p)
    {   p->Init();                                    // инициализация
        // …
        free(p);
    }
return 0;
}

Во-первых, при выделении памяти, естественно, требуется преобразование типа указателя. Во-вторых, обратите внимание, что выделение памяти и инициализация выполняются как два отдельных действия. Мы вынуждены написать в классе специальную функцию инициализации, так как конструктор невозможно «заставить» создать объект именно в выделенном блоке динамической памяти . Вообще-то в общем случае необходимо написать еще и функцию разрушения объекта (и назвать ее, например destroy) , но в данном случае никаких действий по разрушению объекта выполнять не требуется.
Встроенные типы и POD-типы
Именно поэтому в С++ была разработана новая — относительно типобезопасная — система управления динамической памятью. В стандарте работа с динамической памятью описывается в разных местах [1-3.7.3, 5.3.4, 5.3.5, 12.5, 17.4.3.4, 18.4, 20.4], поэтому составить целостную картину не просто. Начнем с самых простых примеров создания динамических объектов встроенных типов.
int *p1 = new int;

Данный оператор выделяет sizeof(int) байтов свободной памяти и записывает адрес этой памяти в переменную-указатель p1. Память никак не инициализируется, даже не обнуляется. Это мало отличается от использования функции malloc(), но преобразование указателя не требуется.
Однако new обладает гораздо большими возможностями. Чтобы присвоить значение динамической переменной, необходимо задать его после типа в круглых скобках, например
int *p2 = new int(100);

В данном случае значение *p2 равно 100. Вообще в скобках может стоять любое выражение, приводимое в данном случае к типу int. Если нужно просто обнулить выделяемую память, то можно использовать конструкцию инициализации нулем:
int *p3 = new int();

С помощью операции new можно создать даже константный динамический объект, например
const int *pp = new const int(3);

Конечно, константный объект обязан быть инициализирован, однако ни Visual C++.NET 2003, ни C++ Builder 6 не выдают ни сообщения об ошибке, ни даже предупреждения, если константный объект создается без инициализации
const int *pp = new const int;            // явная ошибка не диагностируется

Случайное изменение (например, *pp=0 динамического константного объекта невозможно — компилятор следит за этим. Не проходит даже явная отмена константности
const_cast<int>(*pp) = 1;

Компилятор сообщает, что не может преобразовать const int в «чистое» int. Его, конечно, можно «обмануть», подменив указатель, например, так
int *p = const_cast<int *>(pp); *p = 0;

Однако на программистском сленге такой прием получил название «грязный хак» (hack), поэтому без крайней нужды его применять не следует. Да и зачем тогда создавать динамический объект как константный?
Уничтожение объектов и возврат памяти выполняется операцией delete, например
delete p1;

Естественно, указатель должен быть именно тот, который использовался при создании динамического объекта операцией new. Константный динамический объект уничтожается точно так же
delete pp;

Сама операция delete не обнуляет указатель, однако она «правильно» работает в том случае, если указатель уже нулевой — она просто ничего не делает. Поэтому проверять указатель на ноль перед выполнением уничтожения объекта нет необходимости.
Мы уже использовали операцию new[] при реализации контейнеров (см. гл. 3 «Введение в контейнеры»). С помощью этой операции в С++ имеется возможность создавать динамические массивы, например
int *p = new int[100];

Инициализировать такой массив при создании, к сожалению, невозможно. Отсюда следует, что создавать константный динамический массив встроенного типа смысла не имеет — мы не сможем его инициализировать «легальными» способами. Хотя и C++ Builder 6 и Visual C++.NET 2003 никак не реагируют на создание такого массива,
const int *pp = new const int[100];

тем не менее, попытки присвоить значение элементу массива «пресекают на корню». Для массива имеет смысл создавать динамический массив с константой-указателем, чтобы именно указатель случайно нельзя было изменить, например
int * const pp = new int[100];

Основное преимущество динамического массива состоит в том, что количество элементов можно задавать выражением, вычисляемым во время выполнения программы. Более того, стандарт разрешает создавать динамический массив даже нулевого размера [1 5.3.4/7], например
int t = 0; int *pt = new int[t];

Указатель pt получает корректный адрес, отличающийся от любого другого адреса. Таким образом, нет никакой необходимости проверять значение выражения на ноль перед созданием массива.
Уничтожение динамического массива осуществляется операцией delete[]. Например, удалить динамический массив pt следует так
delete []pt;

Пустые квадратные скобки необходимы. Они говорят компилятору, что указатель адресует массив, а не единичный элемент. Отсутствие скобок не является синтаксической ошибкой (компилятор не выдает никаких сообщений), однако правильность выполнения программы не гарантируется

Пока мы рассматривали только встроенные типы данных. Время жизни динамических объектов встроенных типов начинается с момента выделения памяти и заканчивается в момент возврата памяти. Стандарт [1-3.9] определяет, что объекты встроенных типов относятся к так называемым POD-объектам (Plain Old Data). Кроме встроенных типов к POD-объектам относятся перечисления, указатели, массивы, структуры и объединения (union). Как видим, все типы, изначально определенные в С, относятся к POD-типам. Что касается классов, то POD-классами являются только классы с тривиальным конструктором. Тривиальный конструктор — это конструктор, создаваемый автоматически, и класс при этом должен удовлетворять следующим условиям:
1. Класс не должен содержать виртуальных функций.
2. Все поля в классе должны быть POD-объектами.
3. Если класс является наследником, то базовый класс должен иметь тривиальный конструктор, и наследование не должно быть виртуальным (см. «Множественное наследование» в гл. 12).
На практике это означает, что простой класс-ненаследник без конструкторов и виртуальных функций является POD-классом. В частности, пустой класс является POD-классом. Время жизни POD-объектов определяется так же, как и время жизни объектов встроенных типов.
Если в классе не определены конструкторы, например,
struct Type 
{ int t; };

то возможны три способа создания одиночного динамического POD-объекта:
Type *p1 = new Type;                // по умолчанию
Type *p2 = new Type();                // по умолчанию – инициализация нулем
Type *p3 = new Type (*p2);            // копирование

В первом случае работает конструктор без аргументов, создаваемый по умолчанию; второй вариант тоже сопровождается вызовом конструктора без аргументов, однако дополнительно выполняется инициализация нулем; в третьем варианте вызывается автоматически создаваемый конструктор копирования.
Классы (non-Pod типы)
Любой класс, не удовлетворяющий перечисленным выше условиям , является non-POD типом. Стандарт определяет, что создание динамического non-POD объекта операцией new выполняется в два этапа:
1. Для объекта выделяется необходимое количество свободной памяти.
2. Вызывается конструктор, чтобы проинициализировать выделенную память.
Время жизни динамических non-POD объектов начинается только с момента окончания работы конструктора. Первый шаг для одиночного объекта выполняется функцией выделения памяти operator new(), и функцией operator new[]() — для массива объектов. В стандарте [1 3.7.3, 18.4] эти функции определены так:
void *operator new(std::size_t size) throw(std::bad_alloc);
void *operator new[](std::size_t size) throw(std::bad_alloc);

Отметим, что при невозможности выделить память конструктор не вызывается. Более того, пункт стандарта 5.3.4/17 гласит, что в случае возникновения исключения во время инициализации объекта сначала выполняется возврат выделенной памяти, а затем начинается обработка исключения. Таким образом, механизм new/delete еще и значительно более надежен и безопасен по сравнению с механизмом malloc()/free().
Уничтожение динамического объекта тоже выполняется в два шага: сначала вызывается деструктор, а затем функция возврата памяти. Время жизни динамического объекта заканчивается, когда начинается выполнение кода деструктора. Функции возврата памяти определены в стандарте там же, где и функции выделения памяти, и имеют следующие прототипы:
void operator delete (void *) throw();
void operator delete [](void *) throw();

Как и показанное выше создание динамических POD-объектов, динамический объект произвольного класса можно создать без инициализации.
Type *p1 = new Type;                
Type *p2 = new Type();

При наличии в классе определенного конструктора без аргументов в данном случае после выделения памяти вызывается именно он. Кроме того, мы можем инициализировать динамические объекты (аналогично объектам встроенных типов), если в классе определен конструктор инициализации.
При создании динамического массива объектов конструктор без аргументов вызывается для каждого элемента массива. Подчеркнем еще раз, что вызывается именно конструктор по умолчанию, а не конструктор инициализации.
Создание динамических объектов-констант ничем не отличается от создания динамических констант встроенных типов. Конечно, даже динамически создаваемую константу требуется инициализировать (для этого в классе должен быть определен конструктор инициализации), однако и Visual C++.NET 2003, и C++ Builder 6 «пропускают» отсутствие инициализации. Например, без всяких сообщений транслируется такое объявление
const Type *p1 = new const Type;

Естественно, в этом случае во время выполнения вызывается конструктор без аргументов.
Операция delete осуществляет уничтожение динамических объектов: сначала вызывается деструктор, а затем возвращается память. Возврат памяти выполняется функцией operator delete() для одиночного объекта и для массива — функцией operator delete[](). Как мы уже знаем, эти функции не генерируют исключений. Это гарантирует, что операция уничтожения объекта не преподносит никаких сюрпризов — ведь деструктор тоже не должен генерировать исключений. При уничтожении массива деструктор вызывается для каждого элемента удаляемого массива.
Действия при нехватке памяти
Так как свободная память имеет хотя и большой, но конечный объем, то при очередном запросе памяти может не оказаться. Более того, обычно компилятор отслеживает максимальную величину памяти, запрашиваемой для массива в одном выражении new[]. Это, конечно, зависит от платформы. Например, в системе Visual C++.NET 2003 разрешает «попросить» не более 0xffffffff байт памяти. Компилятор вычисляет значение n*sizeof(тип) и если это значение превышает указанное значение, выводится сообщение об ошибке C2148. Например, следующий оператор в программе является ошибочным
double *ddp = new double[10000000000];

Однако в общем случае, поскольку размер массива может задаваться в виде выражения, компилятор, конечно, не может отследить величину запрашиваемой памяти. Поэтому механизм new/delete обеспечивает проверку запроса во время выполнения. Во всех приведенных выше примерах при отсутствии необходимого объема памяти генерируется стандартное исключение std::bad_alloc, [1 18.4.2.1] с которым мы уже знакомы (см. гл. 4). Естественно, клиент, запрашивающий память, должен отслеживать это исключение. Поэтому, вообще говоря, любой запрос памяти операцией new должен быть внутри контролируемого блока, например
try
{ // запросы памяти операцией new или new[] }
catch(std::bad_alloc)
{ // обработка отказа
}

В механизме new/delete существует альтернативный механизм обработки отказов. Прежде чем сгенерировать исключение, функция operator new() вызывает специальную функцию, которая называется обработчиком new. Стандартный обработчик можно подменить собственным, который должен удовлетворять определенным требованиям, прописанным в стандарте [1-18.4.2.2]. В соответствии с определением
typedef void (*new_handler)();

обработчик не имеет параметров и не возвращает значения. Новый обработчик устанавливается функцией set_new_handler(), которая имеет прототип
new_handler set_new_handler(new_handler my_handler);

Возвращаемое значение означает, что при установке собственного обработчика адрес стандартного можно сохранить в переменной-указателе, а затем восстановить, например
void myHandler() 
{ //…
}
void (*p)() = set_new_handler(myHandler);
//…
set_new_handler(p);

Можно вообще «сбросить» обработчик, задав в качестве параметра 0, например
set_new_handler(0);

В этом случае функция operator new() не будет вызывать обработчик, а сразу сгенерирует исключение.
Пользовательский обработчик должен выполнять одно из следующих возможных действий:
 каким-нибудь образом увеличить объем доступной памяти и вернуться в функцию выделения памяти;
 установить вместо себя другой обработчик new;
 сбросить стандартный обработчик;
 сгенерировать исключение типа bad_alloc или наследника от него;
 вызвать функцию завершения abort() или exit().
Обычно стандартный обработчик подменяется для того, чтобы сообщить о нехватке памяти. Однако можно «повесить» на него и более серьезную работу. Например, мы можем разработать собственную систему распределения динамической памяти [20, 25], а при нехватке памяти наш обработчик будет выполнять функции сборщика «мусора».
Продемонстрируем подмену обработчика на простом примере (листинг 8.3).
//Листинг 8.3. Подмена обработчика new_handler
#include <cstdio>
#include <new>                            // для set_new_handler
using namespace std;
void out_of_memory()                    // собственный обработчик
{ perror("Памяти не хватает!\n");
  exit(1);
}
int main()
{ set_new_handler(out_of_memory); 
  while(true) new char[0x7fffffff];        
}

Память запрашивается и не возвращается, поэтому, в конце-концов, сработает наш обработчик, который выведет на экран сообщение о нехватке памяти и завершит работу программы (без генерации исключений!). Обратите внимание на то, что для вывода сообщения об ошибке используется функция perror(), а не стандартный поток cerr. Дело в том, что для записи сообщения об ошибке в cerr требуется динамическое выделение памяти (а ее-то и нет!).

И еще много чего про new нужно читать...
Ссылки в скобках — это пункты стандарта.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[5]: malloc vs new []
От: LaptevVV Россия  
Дата: 24.01.08 13:44
Оценка:
Здравствуйте, dorofeevilya, Вы писали:

D>Здравствуйте, LaptevVV, Вы писали:


LVV>>Здравствуйте, DemAS, Вы писали:


DAS>>> Хм.. а чем тогда отличается malloc() от new ?

LVV>>Как пишет Герб Саттер — это просто две большие разницы. Не смешивайте их никогда.
LVV>>New может быть реализована с помощью malloc(), а наоборот — нет.
LVV>>malloc(0 просто выделяет память, а при использовании new для неPOD типов вызывается конструктор.

D>Простите, я не в курсе, что значит неPOD тип? Первый раз слышу

См ниже мой пост. А кратенько — это реализованный класс с нетривиальными конструкторами
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: malloc vs new []
От: migel  
Дата: 24.01.08 13:46
Оценка: 4 (1)
Здравствуйте, dorofeevilya, Вы писали:

D>Дело в том, что оператор new, если Вы посмотрите в debugger'е, в результате (после некоторых танцев с бубном) для выделения памяти все равно вызовет все тот же malloc() (дебажную версию, что-то типа _dbg_malloc()), которая в свою очередь вызовет (в случае винды) API-шную HeapAlloc().

Не забываем добавлять что это актуально для MSVC для остальных компиляторлв все может быть несколько по другому.
D> То есть, по сути, new и malloc() — одно и то же.
Ну как только malloc правильно вызовет конструктор вновь созданного объекта тогда да
Не путайте implementation specific с глобальными идиомами.
... << RSDN@Home 1.2.0 alpha rev. 719>>
Re[4]: malloc vs new []
От: DemAS http://demas.me
Дата: 24.01.08 14:47
Оценка:
Здравствуйте, LaptevVV, Вы писали:

Спасибо. Можно я по ходу буду вопросы задавать?

LVV>В автоматической памяти размещаются локальные не статические объекты, которые объявляются в любом блоке, в том числе в теле любой функции. В частности, переменные, объявленные в теле главной функции, тоже являются локальными. Память таким объектам выделяется в момент объявления, а уничтожаются такие объекты в конце области видимости. Естественно, наиболее подходящей реализацией является размещение локальных объектов в стековой памяти (хотя в стандарте об этом нет ни слова).


Я правильно понял, что память под все переменные объявленные в функции будет выделена в момент вызова этой функции и освобождена в момент выхода из функции?
Это же относится и к методам/переменным, объявленным в методе класса?


LVV>Уничтожение объектов и возврат памяти выполняется операцией delete, например

LVV>
delete p1;

LVV>Естественно, указатель должен быть именно тот, который использовался при создании динамического объекта операцией new.

А вот так корректно делать:
     int *p1 = new int();
     int *p2 = p1;
     delete p2;

?
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[5]: malloc vs new []
От: LaptevVV Россия  
Дата: 25.01.08 06:39
Оценка: 4 (1)
Здравствуйте, DemAS, Вы писали:

DAS> Я правильно понял, что память под все переменные объявленные в функции будет выделена в момент вызова этой функции и освобождена в момент выхода из функции?

DAS> Это же относится и к методам/переменным, объявленным в методе класса?
Да.
Причем размер стека ограничен, поэтому большой локальный массив может вызвать проблемы.

LVV>>Уничтожение объектов и возврат памяти выполняется операцией delete, например

LVV>>
delete p1;

LVV>>Естественно, указатель должен быть именно тот, который использовался при создании динамического объекта операцией new.

DAS> А вот так корректно делать:

DAS>
DAS>     int *p1 = new int();
DAS>     int *p2 = p1;
DAS>     delete p2;
DAS>

DAS> ?
Это классика — висячая ссылка. Было две ссылки на одну и ту же память. По одной из них память возвращена. Вторая "провисла".
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[6]: malloc vs new []
От: Murom Россия  
Дата: 25.01.08 07:03
Оценка:
Здравствуйте, LaptevVV, Вы писали:

DAS>> А вот так корректно делать:

DAS>>
DAS>>     int *p1 = new int();
DAS>>     int *p2 = p1;
DAS>>     delete p2;
DAS>>

DAS>> ?
LVV>Это классика — висячая ссылка. Было две ссылки на одну и ту же память. По одной из них память возвращена. Вторая "провисла".

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

Висячие ссылки — это несколько не то, что написано в коде.
- Eugeny
Re[7]: malloc vs new []
От: AlexCrush Россия  
Дата: 25.01.08 08:20
Оценка:
Здравствуйте, Murom, Вы писали:

DAS>>> А вот так корректно делать:

DAS>>>
DAS>>>     int *p1 = new int();
DAS>>>     int *p2 = p1;
DAS>>>     delete p2;
DAS>>>

DAS>>> ?

Просто после delete p2 использование указателя p1 приведет к непонятно чему (UB), так как память, на которую указывает p1 уже освобождена. Если после этого изменить сам указатель p1 (типа p1 = new int); — то потом можно снова им пользоваться.
Re[7]: malloc vs new []
От: LaptevVV Россия  
Дата: 25.01.08 09:13
Оценка:
Здравствуйте, Murom, Вы писали:

M>Простите, что значит висячая ссылка??? Вообще это указатель, а не ссылка.

Имеется ввиду не конструкция языка С++, а смысл.
M>Если вы про висячие указатели, то выходит все формальные аргументы функций, которые являются указателями тоже висячие?
При отсутствии реального вызова это пофигу. А при реальном вызове они получают конкретные значения.
M>Висячие ссылки — это несколько не то, что написано в коде.
Я ж говорю, речь идет о смысле кода, а не о конструкциях С++
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.