Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.64/47: Рейтинг темы: голосов - 47, средняя оценка - 4.64
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 21
1

О перевыделении памяти для массива объектов

28.07.2013, 17:04. Показов 8685. Ответов 23
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Мне необходимо сделать динамический массив объектов класса, который будет расширяться при необходимости.
Понятно, что для такого существует выделение через malloc и перевыделение через realloc, но malloc не годится для объектов, тк не вызывает конструктор. Посоветуйте максимально эффективный с точки зрения производительности вариант пожалуйста (думал над выделением новой памяти через new[], копирования из существующего массива объектов в новый и удаление исходного, но мне вариант это показался некрасивым). Готовые решения типа std::vector использовать нельзя.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.07.2013, 17:04
Ответы с готовыми решениями:

Освобождение памяти для объектов производного класса
Всем привет. Не могу найти инфу в интернете, всё перерыл, но понял что случай специфичный у меня....

Резервирование памяти/освобождение памяти для трехмерного массива
Необходимо создать трехмерный массив (A), в котором элементы вдоль направления Z выли бы выровнены...

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

Метод для массива объектов класса
Существует класс mybook, в котором автор, название книги и год издания являются полями данных....

23
5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
28.07.2013, 17:07 2
Цитата Сообщение от CatsCanFly Посмотреть сообщение
думал над выделением новой памяти через new[], копирования из существующего массива объектов в новый и удаление исходного, но мне вариант это показался некрасивым
realloc, наверное, то же самое делает.
0
150 / 137 / 35
Регистрация: 29.07.2012
Сообщений: 709
28.07.2013, 17:11 3
Мне кажется не получится, т.к при новом выделении сотрутся старые данные. Как вариант заранее обьявлять большое кол-во чтоб хватило
0
alsav22
28.07.2013, 17:19
  #4

Не по теме:

Цитата Сообщение от Bend3r Посмотреть сообщение
Мне кажется не получится, т.к при новом выделении сотрутся старые данные.
Это о чём?

0
150 / 137 / 35
Регистрация: 29.07.2012
Сообщений: 709
28.07.2013, 17:32 5
Цитата Сообщение от alsav22 Посмотреть сообщение

Не по теме:


Это о чём?

Ну вот пример.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int *mas = new int[10];
for(int i = 0; i < 10; i++)
{
    mas[i] = i;
}
for(int i = 0; i < 10; i++)
{
    cout << mas[i] << " ";
}
 
mas = new int[20]; //пытаюсь увеличить размерность
 
for(int i = 0; i < 10; i++)
{
    cout << mas[i] << " ";
}
В этом же массиве необходимо увеличить размерность. Я увеличиваю, но старые данные стираются. Я про это имел ввиду. Хотя может возможно как-то можно увеличить размерность массива, без удаления старых данных.
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,736
Записей в блоге: 1
28.07.2013, 18:02 6
Цитата Сообщение от Bend3r Посмотреть сообщение
Я увеличиваю, но старые данные стираются.
Есть такая вещь, как копирование. Выделяем новую память, копируем данные из старой, освобождаем старую память.
0
150 / 137 / 35
Регистрация: 29.07.2012
Сообщений: 709
28.07.2013, 18:05 7
Цитата Сообщение от Croessmah Посмотреть сообщение
Есть такая вещь, как копирование. Выделяем новую память, копируем данные из старой, освобождаем старую память.
Пример покажите пожалуйста.
0
5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
28.07.2013, 18:17 8
Цитата Сообщение от Bend3r Посмотреть сообщение
Пример покажите пожалуйста.
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
int *mas = new int[10];
for(int i = 0; i < 10; i++)
{
    mas[i] = i;
}
 
for(int i = 0; i < 10; i++)
{
    cout << mas[i] << " ";
}
cout << endl; 
 
int *mas2 = new int[20]; 
 
for(int i = 0; i < 10; i++)
{
    mas2[i] = mas[i];
}
 
delete [] mas;
mas = mas2;
 
for (int i = 10; i < 20; ++i)
{
    mas[i] = i;
}
 
for(int i = 0; i < 20; i++)
{
    cout << mas[i] << " ";
}
 
delete [] mas;
0
Неэпический
17870 / 10635 / 2054
Регистрация: 27.09.2012
Сообщений: 26,736
Записей в блоге: 1
28.07.2013, 18:32 9
Цитата Сообщение от Bend3r Посмотреть сообщение
Пример покажите пожалуйста.
http://ideone.com/oUNnc6
0
150 / 137 / 35
Регистрация: 29.07.2012
Сообщений: 709
28.07.2013, 18:43 10
Цитата Сообщение от alsav22 Посмотреть сообщение
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
int *mas = new int[10];
for(int i = 0; i < 10; i++)
{
    mas[i] = i;
}
 
for(int i = 0; i < 10; i++)
{
    cout << mas[i] << " ";
}
cout << endl; 
 
int *mas2 = new int[20]; 
 
for(int i = 0; i < 10; i++)
{
    mas2[i] = mas[i];
}
 
delete [] mas;
mas = mas2;
 
for (int i = 10; i < 20; ++i)
{
    mas[i] = i;
}
 
for(int i = 0; i < 20; i++)
{
    cout << mas[i] << " ";
}
 
delete [] mas;
Вы тут используете 2 массива. А я имел ввиду про 1 массив.
0
5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
28.07.2013, 18:55 11
Цитата Сообщение от Bend3r Посмотреть сообщение
Вы тут используете 2 массива. А я имел ввиду про 1 массив.
А я имел ввиду это:
Цитата Сообщение от Croessmah Посмотреть сообщение
Есть такая вещь, как копирование. Выделяем новую память, копируем данные из старой, освобождаем старую память.
Цитата Сообщение от Bend3r Посмотреть сообщение
Пример покажите пожалуйста.
Про один массив ещё что-то непонятно?
0
150 / 137 / 35
Регистрация: 29.07.2012
Сообщений: 709
28.07.2013, 18:57 12
Все понятно.
0
415 / 411 / 95
Регистрация: 06.10.2011
Сообщений: 832
28.07.2013, 19:24 13
http://ideone.com/WQ63ec
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
 
static int default_constructed = 0;
static int constructed = 0;
static int copied = 0;
static int moved = 0;
static int destroyed = 0;
 
struct Foo
{
    std::string attr1;
    std::vector<int> attr2;
 
    Foo() : attr1(), attr2() { ++default_constructed; }
 
    Foo(const std::string &str,
        const std::vector<int> &v) :
            attr1(str), attr2(v) { ++constructed; }
 
    Foo(Foo &&x) :
            attr1( std::move(x.attr1) ),
            attr2( std::move(x.attr2) ) { ++moved; }
 
    Foo(const Foo &x) : Foo(x.attr1, x.attr2) { ++copied; }
 
    ~Foo() { ++destroyed; }
};
 
int main()
{
    std::allocator<Foo> alloc;
 
    // выделим место под 100 объектов Foo
    Foo *array100 = alloc.allocate(100);
 
    // запишем кол-во
    size_t size = 100;
 
    // и сконструируем столько же
    std::uninitialized_fill( array100,
                             array100 + size,
                             Foo("string", {1000, 42}) ); // constructed = 1 (ref)
                                                          // copy constructed = 100
                                                          // destroyed = 1
 
    // увеличим место - 1000
    Foo *array1000 = alloc.allocate(1000);
    size_t new_size = 1000;
 
    // объекты array100 нужно переместить в новое место
    // если тип обладает перемещающим конструктором, то будет использован именно он
    std::uninitialized_copy( std::make_move_iterator(array100),
                             std::make_move_iterator(array100 + size),
                             array1000 ); // move constructed = 100
 
    // инициализируем остальные 900 элементов
    std::uninitialized_fill( array1000 + size,
                             array1000 + new_size,
                             Foo("string v2", {1000, 87}) ); // constructed = 1 (ref)
                                                             // copy constructed = 900
                                                             // destroyed = 1
 
    // объекты array100 больше не валидны
    std::for_each(array100, array100 + size, [&alloc](Foo &x) { x.~Foo(); } );
                                                            // destroyed = 100
 
    // освободим место под array100
    alloc.deallocate(array100, size);
    array100 = nullptr;
 
    // обновим размер
    size = new_size;
 
    // array1000 больше не нужен
    // уничтожим объекты
    std::for_each(array1000, array1000 + size, [&alloc](Foo &x) { x.~Foo(); } );
                                                            //destroyed = 1000
 
    // освободим память
    alloc.deallocate(array1000, size);
 
    // перестраховка
    array1000 = nullptr;
 
    std::cout << "Objects default constructed = " << default_constructed
              << "\nObjects constructed = " << constructed
              << "\nObjects copy constructed = " << copied
              << "\nObjects move constructed = " << moved
              << "\nObjects destroyed = " << destroyed;
 
    return 0;
}
1
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 21
03.08.2013, 11:57  [ТС] 14
Olivеr, Спасибо, но у меня почему то нет функции make_move_iterator (конечно, файл <iterator> подключен). Использую VC++ 2008, как я понял из гугла, make_move_iterator есть только в новом стандарте, который 2008 студией не поддерживается. А можно показать пример максимально простой? STL я еще не изучал, и использовать ее не желательно к тому же, необходимо изучить максимально подробно работу с памятью для объектов, а не пользоваться готовыми решениями STL (задача то не практическая а в целях изучения).
Суть такова, у меня есть класс, который является максимальноп простой реализацией динамического расширяемого массива объектов, например:
C++
1
2
3
4
5
6
7
8
9
10
11
class CArray
{
private:
    SomeClass* arr;
    size_t size;
    CArray() : size(10)
    {
        arr = new SomeClass[10];
    }
    //...
}
Сам класс SomeClass так же содержит в себе указатель на динамический массив и освобождает от него память в своем деструкторе:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
class SomeClass
{
    int* smth;
    SomeClass()
    {
        smth = new int[20];
    }
    //...
    ~SomeClass()
    {
        delete[] smth;
    }
}
Допустим, мы создаем метод void resize(size_t new_size); для CArray, где копируем содержимое массива в выделенный массив нового размера и удаляем старый:
C++
1
2
3
4
5
6
void CArray::resize(size_t new_size)
{
    SomeClass* temp = new SomeClass[new_size];
    memcpy(temp, this->arr; sizeof(SomeClass) * new_size); // ??? не уверен что так хорошо делать
    delete[] arr;
}
Так вот, при удалении старого массива в этом методе вызовется и деструктор для объектов класса SomeClass, в котором будет освобождена память в которой хранились его собственные массивы, что в результате делает копирование бессмысленным - указатели в скопированных на новое место объектах остались, а память на которую они указывали мы потеряли. С другой стороны отказываться от освобождения памяти в деструткоре SomeClass нельзя, это необходимо в остальных случаях его использования. Надеюсь я понятно объяснил суть своей проблемы. Как понимаю, самый логичный ответ - не вызывать в методе resize деструкторы для содержащихся в массиве объектов, но вот как это сделать? И правильно ли это? В общем, подскажите как решить эту проблему, желательно максимально подробно и без использования готовых решений из stl и других библиотек, а так, что бы было понятно, как это работает на самом деле. Буду очень сильно благодарен
0
~ Эврика! ~
1256 / 1005 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
03.08.2013, 12:19 15
Цитата Сообщение от CatsCanFly Посмотреть сообщение
Как понимаю, самый логичный ответ - не вызывать в методе resize деструкторы для содержащихся в массиве объектов, но вот как это сделать? И правильно ли это? В общем, подскажите как решить эту проблему, желательно максимально подробно и без использования готовых решений из stl и других библиотек, а так, что бы было понятно, как это работает на самом деле. Буду очень сильно благодарен
Решение простое: никогда не хранить в контейнерах объекты, не являющиеся значениями. Объект, который нельзя просто так взять и скопировать — это не значение. Объект, деструкторы которого влияют не только на него самого — это не значение. Самый простой способ превратить объекты в значения: хранить указатели на объекты. Желательно какой-нибудь shared_ptr, а не просто голый указатель, потому что тогда не придётся танцевать с бубном, чтобы стандартые алгоритмы STL работали правильно и не теряли объекты.

Ах да, и никаких memcpy() для не POD-типов (читай: тупо интов, флоатов, или там сишных структурок).
0
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 21
03.08.2013, 12:28  [ТС] 16
Цитата Сообщение от OhMyGodSoLong Посмотреть сообщение
Решение простое: никогда не хранить в контейнерах объекты, не являющиеся значениями. Объект, который нельзя просто так взять и скопировать — это не значение. Объект, деструкторы которого влияют не только на него самого — это не значение. Самый простой способ превратить объекты в значения: хранить указатели на объекты. Желательно какой-нибудь shared_ptr, а не просто голый указатель, потому что тогда не придётся танцевать с бубном, чтобы стандартые алгоритмы STL работали правильно и не теряли объекты.

Ах да, и никаких memcpy() для не POD-типов (читай: тупо интов, флоатов, или там сишных структурок).
Если никогда не хранить так подобные объекты, то как поступать, когда это все же приходится делать? Например класс - динамический расширяемый массив строк разной длины, ну или хотя бы таких же массивов?
0
4064 / 3318 / 924
Регистрация: 25.03.2012
Сообщений: 12,493
Записей в блоге: 1
03.08.2013, 13:12 17
Цитата Сообщение от OhMyGodSoLong Посмотреть сообщение
Решение простое: никогда не хранить в контейнерах объекты, не являющиеся значениями.
Довольно странное решение. Если у объекта есть корректный конструктор копий, оператор = и деструктор, как же его контейнер сломает? Пример можно? а то я не допёр.

Добавлено через 1 минуту
Цитата Сообщение от CatsCanFly Посмотреть сообщение
Olivеr, Спасибо, но у меня почему то нет функции make_move_iterator (конечно, файл <iterator> подключен). Использую VC++ 2008
некоторые пихают с++11 куда надо и не надо!

Добавлено через 3 минуты
Цитата Сообщение от CatsCanFly Посмотреть сообщение
Так вот, при удалении старого массива в этом методе вызовется и деструктор для объектов класса SomeClass, в котором будет освобождена память в которой хранились его собственные массивы, что в результате делает копирование бессмысленным - указатели в скопированных на новое место объектах остались, а память на которую они указывали мы потеряли.
А кто тебя просил мешать С и С++? Как бы я не уважал Си, но очевидно же! memcpy не вызывает перегруженного оператора =
А в корректном копировании через цикл (или через std::copy) он бы вызвался и сохранил бы нам данные от удаления деструктором.
Правило трёх же! http://ru.wikipedia.org/wiki/%... 0%B8%D0%B5)

Добавлено через 8 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
void CArray::resize(size_t new_size)
{
    SomeClass* temp = new SomeClass[new_size];
    size=std::min(size, new_size);
//memcpy(temp, this->arr; sizeof(SomeClass) * new_size); // !!! уверен, так нельзя делать
    std::copy(arr, arr+size, temp); 
/*альтернативный вариант тоже корректно работает, если оператор = корректно перегружен
    for (size_t i=0; i<size; i++)
        temp[i]=arr[i];
*/
    delete[] arr;
    arr=temp;
}
1
~ Эврика! ~
1256 / 1005 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
03.08.2013, 13:15 18
Цитата Сообщение от Kuzia domovenok Посмотреть сообщение
Довольно странное решение. Если у объекта есть корректный конструктор копий, оператор = и деструктор, как же его контейнер сломает? Пример можно? а то я не допёр.
Никак. То, что вы описали, — это и есть определение объекта-значения.

Цитата Сообщение от Kuzia domovenok Посмотреть сообщение
некоторые пихают с++11 куда надо и не надо!
А некоторые разводят тут луддизм.
0
4064 / 3318 / 924
Регистрация: 25.03.2012
Сообщений: 12,493
Записей в блоге: 1
03.08.2013, 13:18 19
Цитата Сообщение от OhMyGodSoLong Посмотреть сообщение
А некоторые разводят тут луддизм.
И как же это, если человек сам сказал, что у него MSVS2008. Что теперь IDE каждый год переустанавливать?
0
В астрале
Эксперт С++
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
03.08.2013, 13:23 20
Kuzia domovenok, Учитывая, что сейчас текущая версия - MSVC2012, то ДА.
Ну или не пользоваться фичами, но это не значит, что люди на форуме не могут использовать С++11 там где удобно, любой код с использованием С++11 можно переписать на С++03 так-то (ну ок, не берем в расчет variadic templates).
1
03.08.2013, 13:23
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
03.08.2013, 13:23
Помогаю со студенческими работами здесь

Функция для перевыделения памяти для массива
Доброго времени суток, пишу шаблонный класс для массива и никак не могу разобраться с динамическим...

Нужно ли вызывать деструкторы для объектов помувленного массива?
Собственно, сабж. Будет ли правильным вызывать деструкторы элементов массива, которые были...

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

Ручное распределение памяти для массива объектов класса Qt
Всем доброго времени суток, умею в ручную распределять и освобождать память для массивов...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru