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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.92
CatsCanFly
0 / 0 / 0
Регистрация: 14.04.2013
Сообщений: 21
#1

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

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

Мне необходимо сделать динамический массив объектов класса, который будет расширяться при необходимости.
Понятно, что для такого существует выделение через malloc и перевыделение через realloc, но malloc не годится для объектов, тк не вызывает конструктор. Посоветуйте максимально эффективный с точки зрения производительности вариант пожалуйста (думал над выделением новой памяти через new[], копирования из существующего массива объектов в новый и удаление исходного, но мне вариант это показался некрасивым). Готовые решения типа std::vector использовать нельзя.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
28.07.2013, 17:04
Здравствуйте! Я подобрал для вас темы с ответами на вопрос О перевыделении памяти для массива объектов (C++):

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

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

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

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

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

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

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

Не по теме:

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

0
Bend3r
149 / 136 / 18
Регистрация: 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
Croessmah
Эксперт CЭксперт С++
13419 / 7573 / 855
Регистрация: 27.09.2012
Сообщений: 18,643
Записей в блоге: 3
Завершенные тесты: 1
28.07.2013, 18:02 #6
Цитата Сообщение от Bend3r Посмотреть сообщение
Я увеличиваю, но старые данные стираются.
Есть такая вещь, как копирование. Выделяем новую память, копируем данные из старой, освобождаем старую память.
0
Bend3r
149 / 136 / 18
Регистрация: 29.07.2012
Сообщений: 709
28.07.2013, 18:05 #7
Цитата Сообщение от Croessmah Посмотреть сообщение
Есть такая вещь, как копирование. Выделяем новую память, копируем данные из старой, освобождаем старую память.
Пример покажите пожалуйста.
0
alsav22
5421 / 4816 / 442
Регистрация: 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
Croessmah
Эксперт CЭксперт С++
13419 / 7573 / 855
Регистрация: 27.09.2012
Сообщений: 18,643
Записей в блоге: 3
Завершенные тесты: 1
28.07.2013, 18:32 #9
Цитата Сообщение от Bend3r Посмотреть сообщение
Пример покажите пожалуйста.
http://ideone.com/oUNnc6
0
Bend3r
149 / 136 / 18
Регистрация: 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
alsav22
5421 / 4816 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
28.07.2013, 18:55 #11
Цитата Сообщение от Bend3r Посмотреть сообщение
Вы тут используете 2 массива. А я имел ввиду про 1 массив.
А я имел ввиду это:
Цитата Сообщение от Croessmah Посмотреть сообщение
Есть такая вещь, как копирование. Выделяем новую память, копируем данные из старой, освобождаем старую память.
Цитата Сообщение от Bend3r Посмотреть сообщение
Пример покажите пожалуйста.
Про один массив ещё что-то непонятно?
0
Bend3r
149 / 136 / 18
Регистрация: 29.07.2012
Сообщений: 709
28.07.2013, 18:57 #12
Все понятно.
0
Olivеr
412 / 408 / 13
Регистрация: 06.10.2011
Сообщений: 831
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
CatsCanFly
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
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
03.08.2013, 12:19 #15
Цитата Сообщение от CatsCanFly Посмотреть сообщение
Как понимаю, самый логичный ответ - не вызывать в методе resize деструкторы для содержащихся в массиве объектов, но вот как это сделать? И правильно ли это? В общем, подскажите как решить эту проблему, желательно максимально подробно и без использования готовых решений из stl и других библиотек, а так, что бы было понятно, как это работает на самом деле. Буду очень сильно благодарен
Решение простое: никогда не хранить в контейнерах объекты, не являющиеся значениями. Объект, который нельзя просто так взять и скопировать — это не значение. Объект, деструкторы которого влияют не только на него самого — это не значение. Самый простой способ превратить объекты в значения: хранить указатели на объекты. Желательно какой-нибудь shared_ptr, а не просто голый указатель, потому что тогда не придётся танцевать с бубном, чтобы стандартые алгоритмы STL работали правильно и не теряли объекты.

Ах да, и никаких memcpy() для не POD-типов (читай: тупо интов, флоатов, или там сишных структурок).
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.08.2013, 12:19
Привет! Вот еще темы с ответами:

Как правильно создать и вызвать конструктор для массива объектов? - C++
Сам класс class Planet{ public: string name; protected: double diameter; private: int sputniks, number, distance; public: ...

Выделение памяти для массива - C++
верно ли выделил память для массива если нет поправьте, заранее спасибо) class type { private: int ***p; int x, y, z; public: ...

Выделение памяти для массива - C++
Вопроса похожего не нашел, в задаче требуется считать матрицу из текстового файла,выделение хотелось бы реализовать следующим образом: ...

Выделение памяти для массива - C++
Пишу такой код: int main() { int* arr1 = new int; } Всё норм. Теперь такой:


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

Или воспользуйтесь поиском по форуму:
15
Yandex
Объявления
03.08.2013, 12:19
Ответ Создать тему
Опции темы

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