Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.54/37: Рейтинг темы: голосов - 37, средняя оценка - 4.54
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
1

Проверить на выход за границы массива

05.05.2013, 12:39. Просмотров 6829. Ответов 44
Метки нет (Все метки)

ПРивет, помогите пожалуйста, пишу класс - динамический массив, в перегрузке оператора [] нужно проверить на выход за границы, но не знаю как правильно использовать try, catch, throw.
C++
1
2
3
4
5
6
7
8
9
10
11
template <class T, int size>
T & Array<T, size> :: operator [](int index) {
    try {
    if (index < 0 || index >= currentSize)
        throw out_of_range("Index was out of range");
    }
    catch(...) { // что тут писать чтобы поймать из throw
        cout << "error";
    }
    return aPtr[index]; // и как быть тут куда вставить эту строку
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.05.2013, 12:39
Ответы с готовыми решениями:

Выход за границы массива
Выхожу за пределы массива, но вот только не понимаю как. #include &lt;iostream&gt;...

Массивы: Проверка на выход за границы массива
Здравствуйте! Пишу код хождения коня по шахматной доске. Конь пока стоит на...

Как вызвать исключение «выход за границы массива»?
Как вызвать исключение «выход за границы массива»? То есть, чтобы ввели массив...

Исправить выход за границы двумерного динамического массива
Уважаемые форумчане, помогите, проблема в том, что пишет ошибку после...

Почему происходит выход за границы массива в функции Analyze()?
#include &quot;Analyzer.h&quot; #include &quot;HashTable.h&quot; #include &lt;iostream&gt; #include...

44
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
05.05.2013, 20:20  [ТС] 21
задание просто такое, получил такой код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <class T, size_t size>
Array<T, size> & Array<T, size> :: operator = (const Array<T, size> &arrayForAssign) {
    if (this != &arrayForAssign) {
        T *ptr = new T[arrayForAssign.currentSize]; // 1 пункт
        size_t s = arrayForAssign.currentSize;
        try {      // 2 пункт
            for (size_t i = 0; i < arrayForAssign.currentSize; i++) {
                ptr[i] = arrayForAssign.aPtr[i];
            }
            delete [] aPtr;  // 3 пункт если в копировании исключ не сгенерировалось
            currentSize = s;
            maxSize = arrayForAssign.maxSize;
            aPtr = ptr;
            return *this;
        }
        catch(...) {
            delete [] ptr;   
        }  
    }
    return *this;
}
все ли правильно?
я не понял только где у меня
Цитата Сообщение от Nick Alte Посмотреть сообщение
создаётся сразу инициализированный массив со значениями по умолчанию.
0
Jupiter
Каратель
Эксперт С++
6569 / 3990 / 400
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
05.05.2013, 20:23 22
Цитата Сообщение от Kreativ Посмотреть сообщение
я не понял только где у меня
строка 4
1
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
05.05.2013, 20:27  [ТС] 23
я же просто выделил память и ничего больше
0
Somebody
2799 / 1610 / 251
Регистрация: 03.12.2007
Сообщений: 4,213
Завершенные тесты: 3
05.05.2013, 20:28 24
Так new для каждого элемента вызывает конструктор по умолчанию (для классов).
1
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
05.05.2013, 20:29  [ТС] 25
точно, подскажите тогда как мне переделать
0
OhMyGodSoLong
~ Эврика! ~
1246 / 995 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
05.05.2013, 21:40 26
Цитата Сообщение от Kreativ Посмотреть сообщение
точно, подскажите тогда как мне переделать
Никак. Забейте. Вам это не нужно.

Как сделать exception-safe копирование динамического массива без вызова конструкторов по умолчанию я уже говорил: специальный хитровыедуманным классом. Там строк на 50 кода.
1
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
05.05.2013, 21:54  [ТС] 27
это про scoped_partially_initialized_array ?
0
OhMyGodSoLong
~ Эврика! ~
1246 / 995 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
05.05.2013, 22:02 28
Ага. У него:
  • конструктор, принимающий количество будущих элементов массива и выделяющий кусок сырой памяти;
  • метод init(const T&), инициализирующий следующий элемент;
  • метод get() отдающий готовый кусок памяти с инициализированными элементами;
  • деструктор, дёргающий деструкторы для всего, что было инициализировано, и освобождающий сырую память (всё это при условии, что метод get() ранее не был вызван).
Примитивные выделяторы памяти зовутся void* operator new[](size_t n) и void operator delete[](void *). Первый принимает количество байт и возвращает кусок, второй принимает кусок и освобождает его. Для ручного вызова конструкторов копирования гуглите placement new. Как вызвать деструктор, думаю, догадаетесь.
1
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
06.05.2013, 00:05  [ТС] 29
большое спасибо, сейчас начну делать

Добавлено через 2 часа 0 минут
я пишу класс по пунктам, которые вы перечислили, но кажется я не понял всю логику.
в метод init я буду отправлять по одному элементу, который нужно скопировать, в этом методе будет происходить инициализация внутреннего указателя класса, я так понял, что здесь нужно вызывать констр. копирования вручную?
после того как все элементы будут отправлены в метод init, методом get я должен буду получить все скопированные значения(из внутр. указ.)?
еще нужно будет перегрузить операторы new, delete и в конструкторе память выделять как обычно
p = new T[size];
а где и когда вызывать вручную деструкторы?
0
OhMyGodSoLong
~ Эврика! ~
1246 / 995 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
06.05.2013, 00:41 30
Вот что за петух вас клюнул? У вас не продакшн-левел библиотека массивов, подобные извращения тут ни к чему.

Эта штука нужна для exception-safety при копировании массива. Её задача: или выдать вам в конце концов указатель на массив из корректно скопированных элементов, или аккуратно удалить весь мусор в случае выброса исключения в процессе копирования. Любого исключения, будь-то память не выделилась или конструктор копирования облажался.

Если бы вам кое-кто не подкинул мысль, что конструктор по умолчанию может и не существовать, то достаточно было бы примитивного варианта в три строки со временным массивом.

Перегружать ничего не надо. Это именно что такие функции, которые именно так и вызываются:
C++
1
2
3
T *ptr = reinterpret_cast<T*>(operator new[](N * sizeof(*ptr)));
///
operator delete[](ptr);
malloc() и free(), считайте.

Конструктор копирования с помощью placement new вызвается в том init().

get() возвращает тот указатель на массив, что вернул operator new[](), и в котором проводил инициализацию init(). После этого данный объект забывает этот указатель. Он передал ему тому, кто вызвал get().

Деструкторы вызываются в деструкторе этого класса. Вызывать их надо только для того, что было проинициализировано (надо помнить, какой кусок массива был проинициализирован, а какой — нет). И только в том случае, если get() не был вызван до этого.

Ещё раз говорю: забейте. Если вы не знаете, зачем это надо, то оно вам не надо. YAGNI.
1
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
06.05.2013, 01:00  [ТС] 31
теперь я обязательно должен это сделать )
0
OhMyGodSoLong
~ Эврика! ~
1246 / 995 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
06.05.2013, 01:14 32
Как сделаете, вперёд читать про RAII и умные указатели Так называется общий к вот таким штукам.
0
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
06.05.2013, 18:48  [ТС] 33
наброски класса сделал, только проблема с деструктором, вот сам класс:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#ifndef Ex_h
#define Ex_h
 
#include <iostream>
#include "TArray.h"
 
using namespace std;
 
template <class T, size_t size> class Array;
 
template <class T, size_t size>
class Ex {
    public:
        Ex(size_t s);
        ~Ex();
        void init(const T &elem, size_t n);
        T * get(void);
 
    private:
        size_t s;
        T *p;
};
 
 
template <class T, size_t size>
Ex<T, size> :: Ex(size_t s) {
    this -> s = s;
    p = reinterpret_cast<T*>(operator new[](s * sizeof(*p)));
}
 
 
template <class T, size_t size>
Ex<T, size> :: ~Ex() {
    //delete [] p;
}
 
 
template <class T, size_t size>
void Ex<T, size> :: init(const T &elem, size_t n) {
    new (p + n) T(elem);
    cout << *(p + n) << " "; 
}
 
 
template <class T, size_t size>
T * Ex<T, size> :: get(void) {
    return p;
}
 
#endif
и перегруженный оператор = в моем шаблоне:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <class T, size_t size>
Array<T, size> & Array<T, size> :: operator = (const Array<T, size> &arrayForAssign) {
    if (this != &arrayForAssign) {
        Ex<T, 5> obj(arrayForAssign.currentSize);
        for (size_t i = 0; i < arrayForAssign.currentSize; i++) {
            obj.init(arrayForAssign.aPtr[i], i);
        }       
        delete [] aPtr;
        aPtr = obj.get();
        currentSize = arrayForAssign.currentSize;
        maxSize = arrayForAssign.maxSize;
 
    }
    return *this;
}
подправьте пож-та и подскажите, где деструктор вызывать
0
OhMyGodSoLong
~ Эврика! ~
1246 / 995 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
06.05.2013, 20:11 34
Ага. Теперь вопрос. Второй шаблонный параметр Ex. Он намеренно не используется? Попробуйте ответить на вопрос, что лучше и почему: шаблонный параметр, задающий максимальный размер копируемого массива, или вон та чиселка в конструкторе.

Насчёт деструктора. В Array его вызывать не надо, он сам вызовется. Что он должен делать: 1) вызывать деструкторы для инициализированных элементов массива, на который указывает p; 2) вызывать operator delete [] для самого p; 3) не делать всего этого, если до этого был вызван метод get().

Деструктор в любом случае вызывается: завершилось ли копирование успешно или нет. Но идея в том, что он должен очищать память только в том случае, если копирование завершилось неуспешно (было выполнено частично). Если пользователь Ex забрал массив с помощью get(), то копирование считается выполненным успешно.

Подумайте, как Ex может эффективно хранить информацию о том, что было инициализировано, а что нет. Подсказка: учтите то, что сценарий использования у Ex только один — это оператор присваивания (ещё примерно то же стоит сделать и в конструкторе копирования).

Не по теме:

Не слушайте упоротых, которые верещат, что точка выхода из функции должна быть единственной. if (this == &arrayForAssign) return *this; в начале, а потом ещё один раз return *this; в конце — это нормально. Эффект тот же, читается субъективно понятнее и нет непонятного мегауровня вложенности.

1
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
06.05.2013, 20:52  [ТС] 35
Цитата Сообщение от OhMyGodSoLong Посмотреть сообщение
Второй шаблонный параметр Ex. Он намеренно не используется?
я только вчера узнал про шаблоны классов ) и сделал Ex с этим параметром. Его вообще думаю нужно убрать, в классе Ex макс значение не нужно.

а над этим еще буду думать
Цитата Сообщение от OhMyGodSoLong Посмотреть сообщение
Подумайте, как Ex может эффективно хранить информацию о том, что было инициализировано, а что нет.
Цитата Сообщение от OhMyGodSoLong Посмотреть сообщение
Если пользователь Ex забрал массив с помощью get(), то копирование считается выполненным успешно.
0
Jupiter
06.05.2013, 21:01
  #36

Не по теме:

OhMyGodSoLong, а не проще задействовать уже готовый аллокатор?

0
OhMyGodSoLong
06.05.2013, 21:11
  #37

Не по теме:

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

0
Jupiter
06.05.2013, 21:20
  #38

Не по теме:

std::allocator и std::uninitialized_copy решают проблему

1
OhMyGodSoLong
06.05.2013, 21:30
  #39

Не по теме:

Дайте я вас расцелую :)

0
Nick Alte
Эксперт С++
1647 / 1019 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
07.05.2013, 19:24 40
Цитата Сообщение от OhMyGodSoLong Посмотреть сообщение
специальный хитровыедуманным классом
Что за странная идея?! Чтобы безопасно скопировать массив, достаточно просто перехватывать исключение в операции копирования и удалить уже созданные элементы в обратном порядке:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
size_t i = 0;
try {
    for(; i < size; ++i)
        new(newArray + i) T(srcArray[i]);
} catch (...) {
    for(; i > 0;)
    {
        --i;
        newArray[i].~T();
    }
    deallocate(newArray);
    throw;
}
0
07.05.2013, 19:24
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.05.2013, 19:24

При вызове функции необработанное исключение, выход за границы массива
bool checkprocessed(point data,int xx,int yy,int wind) { bool mark=false;...

Выход итератора за границы list
почему у меня падает программа, когда пытаюсь ввести отсортированные элементы...

Выход за границы. как исправить???
Суто проги в том, чтобы из 2х массивов создать третий элементами которого я...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru