Форум программистов, компьютерный форум CyberForum.ru

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

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 37, средняя оценка - 4.68
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
05.05.2013, 12:39     Проверить на выход за границы массива #1
ПРивет, помогите пожалуйста, пишу класс - динамический массив, в перегрузке оператора [] нужно проверить на выход за границы, но не знаю как правильно использовать 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]; // и как быть тут куда вставить эту строку
}
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
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 Посмотреть сообщение
создаётся сразу инициализированный массив со значениями по умолчанию.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Jupiter
Каратель
Эксперт C++
6543 / 3963 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
05.05.2013, 20:23     Проверить на выход за границы массива #22
Цитата Сообщение от Kreativ Посмотреть сообщение
я не понял только где у меня
строка 4
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
05.05.2013, 20:27  [ТС]     Проверить на выход за границы массива #23
я же просто выделил память и ничего больше
Somebody
2770 / 1583 / 141
Регистрация: 03.12.2007
Сообщений: 4,139
Завершенные тесты: 1
05.05.2013, 20:28     Проверить на выход за границы массива #24
Так new для каждого элемента вызывает конструктор по умолчанию (для классов).
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
05.05.2013, 20:29  [ТС]     Проверить на выход за границы массива #25
точно, подскажите тогда как мне переделать
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
05.05.2013, 21:40     Проверить на выход за границы массива #26
Цитата Сообщение от Kreativ Посмотреть сообщение
точно, подскажите тогда как мне переделать
Никак. Забейте. Вам это не нужно.

Как сделать exception-safe копирование динамического массива без вызова конструкторов по умолчанию я уже говорил: специальный хитровыедуманным классом. Там строк на 50 кода.
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
05.05.2013, 21:54  [ТС]     Проверить на выход за границы массива #27
это про scoped_partially_initialized_array ?
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 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. Как вызвать деструктор, думаю, догадаетесь.
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];
а где и когда вызывать вручную деструкторы?
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 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.
Kreativ
2 / 2 / 0
Регистрация: 22.09.2012
Сообщений: 202
06.05.2013, 01:00  [ТС]     Проверить на выход за границы массива #31
теперь я обязательно должен это сделать )
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
06.05.2013, 01:14     Проверить на выход за границы массива #32
Как сделаете, вперёд читать про RAII и умные указатели Так называется общий к вот таким штукам.
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;
}
подправьте пож-та и подскажите, где деструктор вызывать
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 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; в конце — это нормально. Эффект тот же, читается субъективно понятнее и нет непонятного мегауровня вложенности.

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

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

Не по теме:

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

OhMyGodSoLong
06.05.2013, 21:11
  #37

Не по теме:

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

Jupiter
06.05.2013, 21:20
  #38

Не по теме:

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

OhMyGodSoLong
06.05.2013, 21:30
  #39

Не по теме:

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

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.05.2013, 19:24     Проверить на выход за границы массива
Еще ссылки по теме:

Пользователь вводит с клавиатуры две границы диапазона и число. Проверить, попадает ли число в диапазон C++
C++ При вызове функции необработанное исключение, выход за границы массива
Почему происходит выход за границы? C++

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

Или воспользуйтесь поиском по форуму:
Nick Alte
Эксперт С++
1590 / 982 / 115
Регистрация: 27.09.2009
Сообщений: 1,897
Завершенные тесты: 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;
}
Yandex
Объявления
07.05.2013, 19:24     Проверить на выход за границы массива
Ответ Создать тему
Опции темы

Текущее время: 15:02. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru