2011-02-04 2 views
2

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

Мои вопросы следующие:

  1. Должен ли я использовать таНос в C++, или новый? Если я буду использовать новый, могу ли я использовать realloc?
  2. Когда следует использовать realloc? Каковы последствия его использования с точки зрения производительности и ошибок?
  3. Из приведенных ниже примеров, в какой объектной новой версии я должен использовать? Если ответ зависит от приложения, от чего он зависит?

Большое спасибо, Matt

#include <stdio.h> 
#include <stdlib.h> 

struct myObject 
{ 
    int data; 
    myObject(int i) 
    { 
     data = i; 
    } 
    myObject() 
    { 
     data = 0; 
    } 

}; 

int main(){ 
    int r = 7; 
    int c = 6; 

    printf("Objects using NEW===============================\n"); 
    //notice the triple pointer being assigned a new double pointer array 
    myObject*** objectNew = new myObject** [r]; 

    for(int i=0;i<r;i++) 
    { 
     //objectNew is a 1D array of double pointers, however if we assign another layer of pointers, it becomes a 2D array of pointers to myObject 
     objectNew[i] = new myObject* [c]; 
     for(int j=0;j<c;j++){ 
      objectNew[i][j] = new myObject(10*i+j); 
      //notice that we dereference data (->) 
      printf("objectNew[%2d][%2d]=%02d\n",i,j,objectNew[i][j]->data); 
     } 
    } 
    delete objectNew; 

    printf("Objects using NEW version 2===============================\n"); 
    //notice the triple pointer being assigned a new double pointer array 
    myObject** objectNew2 = new myObject* [r]; 

    for(int i=0;i<r;i++) 
    { 
     //objectNew is a 1D array of double pointers, however if we assign another layer of pointers, it becomes a 2D array of pointers to myObject 
     objectNew2[i] = new myObject [c]; 
     for(int j=0;j<c;j++){ 
      objectNew2[i][j] = myObject(10*i+j); 
      //notice that we dereference data (->) 
      printf("objectNew2[%2d][%2d]=%02d\n",i,j,objectNew2[i][j].data); 
     } 
    } 
    delete objectNew2; 

    printf("Objects using MALLOC===============================\n"); 
    //notice the double pointer being allocated double pointers the size of pointers to myObject 
    myObject** objectMalloc =(myObject**) malloc(sizeof(myObject*)*r); 

    for(int i=0;i<r;i++) 
    { 
     //now we are assigning array of pointers the size of myObject to each double pointer 
     objectMalloc[i] = (myObject*) malloc(sizeof(myObject)*c); 
     for(int j=0;j<c;j++){ 
      objectMalloc[i][j] = myObject(10*i+j); 
      //notice that we access data without dereferencing (.) 
      printf("objectMalloc[%2d][%2d]=%02d\n",i,j,objectMalloc[i][j].data); 
     } 
    } 
    free((void*) objectMalloc); 

    //same as Malloc 
    printf("Objects using CALLOC===============================\n"); 
    myObject** objectCalloc = (myObject**) calloc(r,sizeof(myObject*)); 

    for(int i=0;i<r;i++) 
    { 
     objectCalloc[i] = (myObject*) calloc(c,sizeof(myObject)); 
     for(int j=0;j<c;j++){ 
      objectCalloc[i][j] = myObject(10*i+j); 
      printf("objectCalloc[%2d][%2d]=%02d\n",i,j,objectCalloc[i][j].data); 
     } 
    } 
    free((void*) objectCalloc); 

    printf("Int using NEW===============================\n"); 
    //int is not an object 
    int** intNew = new int* [r]; 

    for(int i=0;i<r;i++) 
    { 
     intNew[i] = new int[c]; 
     for(int j=0;j<c;j++){ 
      intNew[i][j] = 10*i+j; 
      printf("intNew[%2d][%2d]=%02d\n",i,j,intNew[i][j]); 
     } 
    } 
    delete intNew; 

    printf("Int using malloc===============================\n"); 
    int** intMalloc =(int**) malloc(sizeof(int*)*r); 

    for(int i=0;i<r;i++) 
    { 
     intMalloc[i] =(int*) malloc(sizeof(int)*c); 
     for(int j=0;j<c;j++){ 
      intMalloc[i][j] = 10*i+j; 
      printf("intMalloc[%2d][%2d]=%02d\n",i,j,intMalloc[i][j]); 
     } 
    } 
    free((void*) intMalloc); 
    getchar(); 
    return 0; 
} 

ответ

7
  • new и new[] являются знающими конструкторами, функции распределения памяти C не являются.
  • Аналогичным образом, delete и delete [] являются деструкторами, а free - нет.
  • realloc не работает с памятью, выделенной с помощью new, нет никаких стандартов, определенных для функции realloc с функциями управления памятью C++.
  • Не смешивать new и delete с malloc/calloc/realloc и free (т.е. не free любую память, выделенную с new, не delete любую память, выделенную с malloc)

  • Если вы делаете new [] , вы, скорее всего, должны использовать std::vector, который инкапсулирует все это управление памятью для вас.

  • При использовании памяти выделено сырые указатели, вы могли бы быть лучше обслужены с помощью смарт/полу-интеллектуальные указатели, как boost::shared_ptr или boost::scoped_ptr или std::auto_ptr, в зависимости от ваших потребностей.

  • Благодаря Дэвид Thornley для чего это до:

  • Никогда не смешивайте скаляр new и delete с их формами массива, т.е. сделать не delete[] память, выделенную с new и не delete памяти, выделенной с new[]. Неопределенное поведение вокруг.

  • В вашем примере, вы должны использовать new и new[], если необходимо, потому что, как я уже сказал, они знают конструктор, и ваш класс не является типом POD данных, так как он имеет конструктор.

Пожалуйста, смотрите C++ FAQ для получения дополнительной информации:

+1

Кроме того, сочетайте 'new' и' delete' вместе и 'new []' и 'delete []' вместе, и помните, что вы должны иметь один 'delete' или' delete [] 'per' new' или 'новый []'. –

+0

Я предполагаю, что используемый вектор footprint ничтожно мал? – mna

+0

@mna - накладные расходы на память 'std :: vector' зависят от реализации, но он имеет некоторые переменные-члены, такие как указатель на выделенный блок и член (' std :: vector :: size_type', который является typedef ' d из некоторого интегрального типа), удерживающего текущий размер вектора. – birryree

3

1) Должен ли я использовать таНос в C++, или новый? Если я использую новый, могу ли я использовать realloc?

Используйте new. И никогда не используйте realloc с new.

Когда следует использовать realloc? Что такое последствия использования его в терминах производительности и ошибок?

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

0

Должен ли я использовать таНос в C++, или новый? Если я использую новый, могу ли я использовать realloc?

Вы можете использовать malloc в C++; однако в большинстве случаев это сильно обескураживает. Кроме того, если вы звоните malloc, calloc, realloc и т. Д., Вам необходимо использовать free, чтобы освободить память, когда закончите.

Если вы используете new для выделения памяти, вы должны использовать delete, чтобы освободить его.

Подпрограммы C-распределения не имеют безопасности типов. new.

0

Если вы хотите писать программы C++ (!!), не используйте malloc, realloc, free. Это просто не C++-функции.

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

0

В целом, вы должны стараться избегать выделения собственных ресурсов на C++. Большинство (не все) массивов можно сделать с std::vector лучше, чем вы собираетесь делать самостоятельно, особенно потому, что вы делаете ошибку здесь.

Вы размещаете, скажем, intNew и intNew[i]. Тогда вы delete [] intNew; (скобки нужны здесь, оставив их без ошибок), без delete [] в любом из intNew[i]. Одномерные массивы, которые вы выделили, теперь являются утечками памяти и не могут быть освобождены, потому что вы потеряли все ссылки на них. Ни C, ни C++ обычно не имеют сборщика мусора.

Функции распределения памяти C относятся только к памяти. Они не являются безопасными для типов и не вызывают конструкторы или деструкторы. Они могут использоваться с типами данных, которые не требуют ни того, ни другого, но вы должны убедиться, что они этого не делают. (Возможно создание malloc памяти и использование места размещения new для создания объектов, но это более продвинутый.)

Функции распределения памяти на C++ связаны с памятью и объектами. Они, в основном, безопасны по типу и выполняют вызовы конструкторов и деструкторов.Не все объекты можно перемещать безопасно, поэтому нет эквивалента malloc. Трудная часть состоит в том, что вам нужно соответствовать new с delete и new[] с delete[]. У вас есть эта ошибка в вашем коде: delete intNew; должно быть delete [] intNew;.

+0

Спасибо вам большое. Означает ли это, что типичная «удалить ссылку из связанного списка», найденную здесь: http://c-faq.com/~scs/cclass/int/sx8.html, ответ не удаляет удаленный узел. Это тоже утечка памяти? – mna

+0

@mna: Это зависит от того, как были созданы узлы связанного списка. В C очень часто выделяется пространство для большого количества узлов одновременно, поскольку он намного эффективнее во время выполнения и использования памяти, чем множество и множество небольших распределений. Если узлы распределены по одному, то да, необходимо освободить удаленный узел. Если нет, то он не должен (вы не можете освободить только часть того, что вы выделили), но он может быть добавлен в список свободных узлов. Пример упрощен и не учитывает распределение памяти. –