LINUX.ORG.RU

C++ ошибка сегментирования при вызове delete

 ,


0

1

Помогите новичку. Есть такой код:

#include <iostream>
//прочие includ'ы

using namespace std;

template<typename T>
class Heap
{
   T _heap;
public:
   Heap():_heap(0) {}
   Heap(T V): _heap(V) {}
   Heap<T> operator = (T const& cv){ _heap = (T)cv;}
   operator Heap() {return _heap;}
   operator Heap*() {return (Heap*)_heap;}
   bool operator == (T const& cv) 
   {
      return _heap == cv ? true : false;
   }
   bool operator != (T const& cv) 
   {
      return _heap != cv ? true : false;
   }
   ~Heap(){}   
}

typedef Heap<unsigned short int> Cell;
/* тут идут всякие функции, векторы и бла бла бла
   ...
   ...
   ...
*/

int main(int argc, char* argv[])
{
   int ar_size = 100;
   if(argc > 1)
     ar_size = atoi(argv[1]);
   if((ar_size % 2) != 0)
     ar_size--;
   Cell **Area = new Cell *[ar_size];
   for(int i = 0; i <= ar_size; i++)
      Area[i] = new Cell[ar_size];
   /*Что-то происходит...
   ...
   ...
   ...

   Дальше идет очистка памяти.
   вызывается erase для векторов и т.д. и т.п.
*/
   cout<<"Almost ";//проверка - доходит ли до этого места?
   for(int i = 0; i <= ar_size; i++)
      delete[] Area[i];// вот тут проблема, если ar_size <= 100
// все проходит нормально, если больше - ошибка сегментации.
   cout<<"Done"<<endl;//до этого места не всегда доходит
   return 0;
}
Если последний цикл убрать, то заканчивается нормально. Но без него не катит
Кто нибудь сталкивался с подобного рода проблемой? Если да, то пожалуйста опишите способы решения
Заранее благодарен.

Do you know that C++ allocates memory in an array from 0 to specified_size - 1 cells ?

ec_nsk
()

for(int i = 0; i <= ar_size; i++)

Это вообще что? У тебя заведомо не верный размер массива или таки неверное условие?

erfea ★★★★★
()

cout<<«Almost »;//проверка - доходит ли до этого места?

У тебя пробел плохо работает наверное?

anonymous
()
Ответ на: комментарий от frozenix

Два чая этому господину!

ТС-у - никогда так не делайте. Массив массивов в С++ актуален ТОЛЬКО если размеры вложенных массивов различаются. Иначе двумерный массив делается на основе одномерного при помощи индексной арифметики.

AIv ★★★★★
()
Ответ на: комментарий от AIv

Массив массивов в С++ актуален ТОЛЬКО если размеры вложенных массивов различаются. Иначе двумерный массив делается на основе одномерного при помощи индексной арифметики.

ЩИТО?

ТСу: да, массив начинается с 0: 0,1,2,3...99. Потому условие j<100. А сотого эл-та не существует. Вот в сегфолт и выпадает.

drBatty ★★
()
Ответ на: комментарий от AIv

и да, у ТСа массив указателей на массивы. массив массивов возможен только если подмассивы одинаковы. По определению. Только в пхп в массиве могут быть разные штуки.

drBatty ★★
()
Ответ на: комментарий от drBatty

ЩИТО непонятно то? Такая структура данных крайне неэффективна в использовании, не говоря уже о создании/удалении. индексная арифметика, это типа

T* p = new T[Nx*Ny];
p[x+Nx*y] = ...; //доступ к элементу (x,y)

и да, у ТСа массив указателей на массивы. массив массивов возможен только если подмассивы одинаковы.

Согласен, оговорился. Хотя у него подмассивы как раз одинаковы. Но такая шняга работает в С только если размер известен на момент компиляции.

AIv ★★★★★
()
Ответ на: комментарий от AIv

Массив массивов в С++ актуален ТОЛЬКО если размеры вложенных массивов различаются.

Я не буду столь категоричен как вы, но голосую за одномерные массивы - и нагляднее и понятнее. Впрочем об этом и К&R в свое время писали, так что не только для C это справедливо.

andreyu ★★★★★
()
Ответ на: комментарий от drBatty

схренали?

массив массивов возможен только если подмассивы одинаковы. По определению.

массивы массивов никому ничего не должны.

Stil ★★★★★
()
Ответ на: комментарий от AIv

Массив массивов в С++ актуален ТОЛЬКО если размеры вложенных массивов различаются. Иначе двумерный массив делается на основе одномерного при помощи индексной арифметики.

Для статических массивов с известными размерами это одно и то же (компилятор будет сам заниматься индексной арифметикой).

quasimoto ★★★★
()

НЕ выноси моск, сделай типа

template<class T, int SIZE = 5> 
class ..
T _cells[SIZE][SIZE]

Boy_from_Jungle ★★★★
()
Последнее исправление: Boy_from_Jungle (всего исправлений: 1)
Ответ на: комментарий от frozenix

Заменил, все то же самое. Не работает. Книг прочитано много, но опыта маловато.(
g++ и gcc компилируют молча, но работать не хочет

WaldeMar1321
() автор топика

Повторюсь: все прекрасно работает если ar_size == 100, или меньше. Если больше выпадает ошибка сегментации при удалении массива. При остальных действиях с массивом (каким бы его размер не был) все опять же работает прекрасно. заменил

for(int i = 0; i <= ar_size; i++)
на
for(int i = 0; i < ar_size; i++)

изменений нет(

WaldeMar1321
() автор топика
Ответ на: комментарий от AIv

ЩИТО непонятно то? Такая структура данных крайне неэффективна в использовании, не говоря уже о создании/удалении.

1. про «использование» я не был-бы столь категоричен: попробуй изменить число строк в квадратной матрице: для массива массивов придётся делать всю матрицу по новой, для массива указателей на массив достаточно изменить массив указателей.

2. на счёт удаления - разве Over9000 элементов размеров M создать/удалить сложнее, чем один размером Over9000*N? Обоснуй свой ответ.

индексная арифметика, это типа

a[10][20]

как и принято в C/C++

что IRL выгоднее - я не знаю, зависит от задачи и архитектуры.

drBatty ★★
()
Ответ на: схренали? от Stil

массивы массивов никому ничего не должны.

тогда код в студию, где у тебя массив, в сишечке, и с элементами разного размера.

drBatty ★★
()
Ответ на: комментарий от drBatty

1. Согласен, но я обычно под использованием подразумеваю в первую очередь обход. Эффективность обхода зависит от локальности данных... в этом случае кстати куда предпочтительнее рекурсивные массивы.

2. Операции new/delete сами по себе дорогие. Есть разница, дернуть такую операцию один раз или arr_sz раз.

что IRL выгоднее - я не знаю, зависит от задачи и архитектуры.

Ага. То-то народ, как начинает че то оптимизировать, так сразу выделяют память одним куском и потом в нем возякаются... даже со списками кстати.

AIv ★★★★★
()
Ответ на: комментарий от AIv

выделяют память одним куском

Пример:

#include <cassert>
#include <cstdio>

#include <memory>

// (maybe) bad data locality, indirect addressing in the LHS, UB in the RHS.
void a1(int **xs, int n, int i, int j)
{
    assert(xs[i][j] == (*xs)[i * n + j]);
}

// Good data locality, direct addressing in the LHS and RHS.
template<int n> void a2(int xs[][n], int i, int j)
{
    assert(xs[i][j] == (*xs)[i * n + j]);
}

// gcc -S:
// 
// movslq %esi, %rax
// movslq %edx, %rcx
// leal (%rdx,%rsi,8), %edx
// salq	$5, %rax
// subq	$8, %rsp
// addq	%rdi, %rax
// movslq %edx, %rdx
// movl	(%rdi,%rdx,4), %esi
// cmpl	%esi, (%rax,%rcx,4)
// 
void a2_8(int xs[][8], int i, int j)
{
    a2(xs, i, j);
}

template<int m, int n>
void test(int (&xs)[m][n])
{
    for (int i = 0; i < m; ++i)
        for (int j = 0; j < n; ++j)
            xs[i][j] = i + 2 * j;

    for (int i = 0; i < m; ++i)
        for (int j = 0; j < n; ++j)
            assert(xs[i][j] == (*xs)[i * n + j]);

    for (int i = 0; i < m * n; ++i) {
        printf("%2d ", (*xs)[i]);
        if ((i + 1) % n == 0) puts("");
    }

    puts("");
}

// Preallocated contiguous 2D array (int(*)[4][8]) in the .bss.
int data[4][8];

int main()
{
    test(data);

    // Allocate contiguous 2D array (int(*)[4][8]) on the stack.
    int stack[4][8];
    test(stack);

    // Allocate contiguous 2D array (int(*)[4][8]) in the heap.
    std::unique_ptr<int[4][8]> heap(new int[1][4][8]);
    // Convert int(*)[4][8] to int(&)[4][8] and pass it to `test'.
    test(*heap.get());
}

Везде память одним куском, кроме a1 (в которой даже не массивы).

quasimoto ★★★★
()
Ответ на: комментарий от AIv

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

WaldeMar1321
() автор топика
Ответ на: комментарий от AIv

зависит от задачи и архитектуры.

на самом деле, любые структуры имеют право на жизнь.

drBatty ★★
()
Ответ на: комментарий от quasimoto

я уже сказал выше, что оговорился. Да, С-шные массивы массивов массивов ... хороши, но именно потому, что компайлер сам делает из них одномерный массив и сам реализует адресную арифметику.

AIv ★★★★★
()
Ответ на: комментарий от WaldeMar1321

и это delete

Сегфолт поганая ошибка в частности потому, что реальная ошибка может быть совсем не там (гораздо выше), чем вылетает сегфолт. Соберите с ключом -g и запустите из под valgrind - сразу все будет понятно.

AIv ★★★★★
()
Ответ на: комментарий от WaldeMar1321

Почему не подойдет? Очень даже подойдет.

Reset ★★★★★
()
Ответ на: комментарий от AIv

Согласен, но я обычно под использованием подразумеваю в первую очередь обход. Эффективность обхода зависит от локальности данных... в этом случае кстати куда предпочтительнее рекурсивные массивы.

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

Операции new/delete сами по себе дорогие. Есть разница, дернуть такую операцию один раз или arr_sz раз.

никто не заставляет постоянно делать такие массивы. Мало того, можно сразу выделить нужный кусок памяти, и использовать его как массив указателей вместе с массивами.

Ага. То-то народ, как начинает че то оптимизировать, так сразу выделяют память одним куском и потом в нем возякаются... даже со списками кстати.

выделение одного куска никак не отменяет связанной памяти.

drBatty ★★
()
Ответ на: комментарий от Reset

Во-первых, про '<=' уже сказали, во-вторых, в C++ принято использовать std::vector.

+1. Если конечно смысл этой задачи не в изобретении велосипеда.

drBatty ★★
()
Ответ на: комментарий от drBatty

во первых цена обхода часто мала, по сравнению с действиями,

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

во вторых, если выделять один раз и сразу, то данные будут расположены локально.

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

2) Даже если выделять ошметками как ТС, за счет постраничной загрузки и прочих фокусов, в некоторых задачах локальность может оказаться приемлемой.

выделение одного куска никак не отменяет связанной памяти.

Конечно не отменяет, более того все нормальные списки так и сделаны.

AIv ★★★★★
()
Последнее исправление: AIv (всего исправлений: 1)
Ответ на: комментарий от AIv

да, это НЕ определение локальности ес-но.

AIv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.