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

C++

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 153, средняя оценка - 4.65
pito211
 Аватар для pito211
186 / 173 / 8
Регистрация: 22.03.2010
Сообщений: 612
#1

realloc и вызов конструктора - C++

20.05.2011, 13:52. Просмотров 18479. Ответов 35
Метки нет (Все метки)

здраствуйте! мне препод сказал, что можно выделить память оператором new, а потом довыделить её с помощью realloc и каким-то образом вызвать конструкторы для новой памяти(ну или это я так его понял). Как это можно сделать?

задание вобще такое:
Во всех вариантах необходимо первоначально создать шаблон класса для работы с массивом произвольного типа данных. Шаблон должен включать:
указатель, хранящий адрес размещения массива в динамической памяти;
целочисленную переменную, показывающую количество занятых элементов массива;
конструктор без параметров, создающий динамический массив заданного типа, с нулевым количеством занятых элементов;
конструктор копирования;
очистку массива;
метод «обработки массива»;
деструктор.
Далее на основе данного шаблона создать класс для работы со строкой символов, специализировав метод «обработки массива» для вашей конкретной задачи.
я хотел класс allocator использовать, но нельзя((. Пока на примете только один вариант - выделять с помощью new и как только память заполниться выделять участок в два раза крупнее копировать старые данные и подчищать за ними. Есть ещё варианты?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7958 / 4720 / 319
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
20.05.2011, 13:55     realloc и вызов конструктора #2
pito211, Ага. Можно. А еще стрелять себе в голову тоже не запрещается... Это я на тему new и realloc. realloc не реагирует на конструкторы. Да плюс к тому new выделяет свободную память, а realloc/malloc/calloc выделяют память в куче.
oxotnik
 Аватар для oxotnik
1586 / 1063 / 33
Регистрация: 21.08.2008
Сообщений: 4,545
Записей в блоге: 1
20.05.2011, 14:09     realloc и вызов конструктора #3
Цитата Сообщение от ForEveR Посмотреть сообщение
Да плюс к тому new выделяет свободную память, а realloc/malloc/calloc выделяют память в куче.
Как это понять?
new изнутри это тот же malloc плюс вызов конструктора
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17192 / 5446 / 337
Регистрация: 30.03.2009
Сообщений: 14,794
Записей в блоге: 26
20.05.2011, 14:27     realloc и вызов конструктора #4
Цитата Сообщение от pito211 Посмотреть сообщение
мне препод сказал, что можно выделить память оператором new, а потом довыделить её с помощью realloc
Нельзя вперемешку использовать new/delete и malloc/realloc/free. Точнее можно, но с непредсказуемыми последствиями. В Си++ нет встроенной конструкции для перевыделения памяти, а потому такое делается через malloc/realloc. Если препод бестолковый из разряда "у меня работает, значит можно", то сделай new/realloc, но для себя надо понимать, что это интерфейсы разных уровней, которые в общем случае не следует перемешивать

Добавлено через 2 минуты
Цитата Сообщение от oxotnik Посмотреть сообщение
new изнутри это тот же malloc плюс вызов конструктора
На самом деле вызов конструктора - это снаружи new, а не изнутри (т.е. вызов конструктора ставит компилятор, а не реализация оператора new). По поводу того, что "это тот же malloc" - это постфактум в реализациях. Но, как мне кажется, никто не гарантирует, что new это в чистом виде обёртка вокруг malloc'а и что там никаких дополнительных действий не делается
oxotnik
 Аватар для oxotnik
1586 / 1063 / 33
Регистрация: 21.08.2008
Сообщений: 4,545
Записей в блоге: 1
20.05.2011, 14:41     realloc и вызов конструктора #5
Цитата Сообщение от Evg Посмотреть сообщение
Если препод бестолковый из разряда "у меня работает, значит можно"
Препод как раз толковый. Думаю тут задача стоит изучить "изнутри" оператор new как он работает.
А по теме: для своего класса надо переопределить new.

Добавлено через 12 минут
Цитата Сообщение от Evg Посмотреть сообщение
На самом деле вызов конструктора - это снаружи new
да с вызовом конструктора внутри погорячился... ибо на стеке нет никакого new но конструктор вызывается, следовательно new тут не причем

Цитата Сообщение от Evg Посмотреть сообщение
что new это в чистом виде обёртка вокруг malloc'а и что там никаких дополнительных действий не делается
ну еще проверки и вызов исключения если нехватает памяти:
Код
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
        {       // try to allocate size bytes
        void *p;
        while ((p = malloc(size)) == 0)
                if (_callnewh(size) == 0)
                {       // report no memory
                static const std::bad_alloc nomem;
                _RAISE(nomem);
                }

        return (p);
        }
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7958 / 4720 / 319
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
20.05.2011, 15:00     realloc и вызов конструктора #6
oxotnik, Ну одна из реализаций. Кто сказал что она единственная?

Добавлено через 4 минуты
Тем более что реализовать что-то вроде realloc средствами С++ ну вообще не проблема. Правда он будет не оптимизированный да и вообще, но все же.
pito211
 Аватар для pito211
186 / 173 / 8
Регистрация: 22.03.2010
Сообщений: 612
20.05.2011, 15:16  [ТС]     realloc и вызов конструктора #7
вы уже чё то не то обсуждаете

лучше расскажите как
Цитата Сообщение от ForEveR Посмотреть сообщение
[b]
реализовать что-то вроде realloc средствами С++
без кода, в общих чертах, если не затруднит
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17192 / 5446 / 337
Регистрация: 30.03.2009
Сообщений: 14,794
Записей в блоге: 26
20.05.2011, 15:23     realloc и вызов конструктора #8
Цитата Сообщение от oxotnik Посмотреть сообщение
Препод как раз толковый. Думаю тут задача стоит изучить "изнутри" оператор new как он работает.
А по теме: для своего класса надо переопределить new.
В первом посте написано: "препод сказал, что можно выделить память оператором new, а потом довыделить её с помощью realloc", а в задании про переопределение оператора new ничегоне сказано. Так что хз что тут: либо препод неправильный, либо автор слова препода исковеркал

Цитата Сообщение от oxotnik Посмотреть сообщение
ну еще проверки и вызов исключения если нехватает памяти
Проверки фиг с ними. Я имел в виду то, что new по аналогии с malloc'ом ожет выделять чуть больше памяти, чтобы хранить воспомогательную информацию и при этом возвращать немного не то, что вернул malloc. В этом отношении при комбинации new/realloc можно конкретно накосячить

Цитата Сообщение от ForEveR Посмотреть сообщение
Тем более что реализовать что-то вроде realloc средствами С++ ну вообще не проблема
В одной из тем обсуждали, что встроенных аналогов realloc'а нет, только всякие контейнеры типа std::vector (которые по сути обёртки над malloc/realloc)
oxotnik
 Аватар для oxotnik
1586 / 1063 / 33
Регистрация: 21.08.2008
Сообщений: 4,545
Записей в блоге: 1
20.05.2011, 15:30     realloc и вызов конструктора #9
Цитата Сообщение от Evg Посмотреть сообщение
Я имел в виду то, что new по аналогии с malloc'ом ожет выделять чуть больше памяти, чтобы хранить воспомогательную информацию и при этом возвращать немного не то, что вернул malloc. В этом отношении при комбинации new/realloc можно конкретно накосячить
Посмотрел реализацию gcc Студии, борланда, везде практически одно и тоже.
Выделяется память через malloc делаются проверки, и указатель возвращается.
Под какую такую информацию надо резервировать доп. память?
А что тогда sizeof будет показывать?
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17192 / 5446 / 337
Регистрация: 30.03.2009
Сообщений: 14,794
Записей в блоге: 26
20.05.2011, 15:45     realloc и вызов конструктора #10
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от oxotnik Посмотреть сообщение
Под какую такую информацию надо резервировать доп. память?
А что тогда sizeof будет показывать?
glibc'шная реализация malloc'f при каждом обращении выделяет памяти больше, чем нужно. И в дополнительную память кладёт магическое число, чтобы делать контроль внутри realloc'а и free. Схематично что-то типа того:

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
void*
malloc (long size)
{
  char *p;
 
  /* Функцию, которая по-настоящему выделяет память, условно назвал get_mem.
   * В реальности там всё куда сложнее, я просто хочу пояснить принцип
   * Здесь мы выделили дополнительный фрагмент памяти */
  p = get_mem (sizeof (long) + size);
 
  /* В начало реально выделенной памяти кладём магическое число */
  *((long*)p) = 0xdeadbeef;
 
  /* Наружу отдаём память, лежащую за магическим числом */
  return p + sizeof (long);
}
 
void free (void *ptr)
{
  char *p;
 
  /* Наружу мы отдавали результат get_mem со сдвигом. Теперь вернём значение
   * обратно, получив таким образом то, что реально выдал get_mem */
  p = ptr - sizeof (long);
 
  if (*((long*)p) != 0xdeadbeef)
  {
    /* АХТУНГ! Магическое число не совпадает. Вероятнее всего в free подали
     * совсем не то, что вернул malloc */
  }
 
  /* Название функции free_mem условное */
  free_mem (p);
}
Пи таком построении всё читерство с магическими числами сосредоточено внутри интерфейсов malloc и free и для пользователя оно всё прозрачно. Т.е. пользовтатель получил указатель, который вернул malloc, а затем отдал этот указатель в free. То, что это не есть результат настоящего выделения памяти, а результат со сдвигом, снаружи никак не проявляется.

Ровно таким же образом могут быть реализованы операторы new и delete. Т.е. new внутри себя использует malloc, но наружу может отдать немного не то, что вернул malloc

Пример, как это работает в glibc под linux'ом:

C
1
2
3
4
5
6
7
8
9
10
11
#include <stdlib.h>
 
int main (void)
{
  int *p;
  
  p = malloc (100);
  /* Некорректный вызов free */
  free (p + 10);
  return 0;
}
На исполнении видим, что сработал Ахтунг

Код
$ gcc t.c
$ ./a.out
*** glibc detected *** ./a.out: free(): invalid pointer: 0x0804b030 ***
Aborted
oxotnik
 Аватар для oxotnik
1586 / 1063 / 33
Регистрация: 21.08.2008
Сообщений: 4,545
Записей в блоге: 1
20.05.2011, 15:55     realloc и вызов конструктора #11
Evg, а где тогда хранится размер выделяемой памяти, что бы free(*p) правильно сработал?
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17192 / 5446 / 337
Регистрация: 30.03.2009
Сообщений: 14,794
Записей в блоге: 26
20.05.2011, 16:01     realloc и вызов конструктора #12
Цитата Сообщение от oxotnik Посмотреть сообщение
Evg, а где тогда хранится размер выделяемой памяти, что бы free(*p) правильно сработал?
Например, там же, где и магическое число. Это всё зависит от реализации malloc'а. Реально malloc внутри себя выделяет память с точностью до страницы (чтобы при куче маленьких выделений памяти поменьше обращаться к системе). Там ещё целая куча всяких наноалгоритмов

Вот, например, одна из реализаций malloc'а: тыц

Добавлено через 35 секунд
Цитата Сообщение от oxotnik Посмотреть сообщение
А что тогда sizeof будет показывать?
sizeof от чего?
oxotnik
 Аватар для oxotnik
1586 / 1063 / 33
Регистрация: 21.08.2008
Сообщений: 4,545
Записей в блоге: 1
20.05.2011, 16:09     realloc и вызов конструктора #13
Цитата Сообщение от Evg Посмотреть сообщение
sizeof от чего?
вопрос снимается...
ЗЫ: помогли называется пацану... (ТС который)
pito211
 Аватар для pito211
186 / 173 / 8
Регистрация: 22.03.2010
Сообщений: 612
20.05.2011, 16:15  [ТС]     realloc и вызов конструктора #14
спасибо всем за развёрнутый ответ
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7958 / 4720 / 319
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
20.05.2011, 16:24     realloc и вызов конструктора #15
pito211, Да элементарно. Подход как у вектора.
Используем себе массив - нужно больше - вызываем специальную самописную функцию, перераспределяющую память, путем создания нового указателя (с большим размером выделенной памяти) и копирования туда элементов, удалением старого указателя и присваиванием старому указателю адрес нового, изменение переменной размера для старого.
Ну и собственно-то все.
pito211
 Аватар для pito211
186 / 173 / 8
Регистрация: 22.03.2010
Сообщений: 612
20.05.2011, 16:34  [ТС]     realloc и вызов конструктора #16
ну я понял, просто я думал есть какие-то более рациональные варианты. Пока вы охотник с Evg обсуждали тут... Я накатал следующее:

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
template <typename T> class vector
    {
        typedef unsigned short int uint;
    private:
        T*          arr;
        uint        _capacity,
                    _size;
 
        bool        resize();
 
    public:
        vector();
        vector(const vector<T> &Q);
 
        T operator[](const uint &index);
 
        void        push_back(const T &value);
        
        uint        size();
        bool        empty();
 
 
        ~vector();
    };
 
    template <typename T> vector<T>::vector() : _size(0), _capacity(0)
    {
        arr = NULL;
    }
 
    template <typename T> vector<T>::~vector() 
    {
        delete[] arr;
    }
 
    template <typename T> vector<T>::vector(const vector<T> &Q) 
    {
        this->_size = Q._size;
        this->_capacity = Q._capacity;
 
        arr = new T[_capacity];
        for (uint i = 0; i != _size; i++) {
            arr[i] = Q.arr[i];
        }
 
 
    }
 
    template <typename T> void vector<T>::push_back(const T &value) 
    {
        if (  empty()  ) 
        {
            arr = new T(value);
            _capacity = _size = 1;
 
        }
        else 
        {
            if (  _size == _capacity  ) 
            {
                resize();   
            }
            arr[_size] = value;
            _size++;
        }
 
    }
 
    template <typename T> T vector<T>::operator[](const uint &index)
    {
        return arr[index];
    }
 
    template <typename T> bool vector<T>::resize() 
    {
        T* NewArea = new T[_capacity * 2];
        for (uint i = 0; i != this->_size; i++) {
            NewArea[i] = this->operator[](i);
        }
 
        _size == 1 ? delete arr : delete[] arr;
 
        arr         =    NewArea;
        _capacity   *=   2;
 
        return true;
        
    }
 
    template <typename T> bool vector<T>::empty() {
        return (_size == 0);
    }
когда size подходит к capacity я выделяю вдвоё больший кусок. Так примерно должно быть?
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17192 / 5446 / 337
Регистрация: 30.03.2009
Сообщений: 14,794
Записей в блоге: 26
20.05.2011, 16:41     realloc и вызов конструктора #17
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от pito211 Посмотреть сообщение
когда size подходит к capacity я выделяю вдвоё больший кусок.
Это не есть хорошо, потому что чем больше памяти будешь выделять, тем больше будет вероятность того, что память жрётся неэффективно (да ещё и экспотенциально). Обычно делают так, что выделяют некий квант (например, 1024 элемента) и выделяют память квантами. Т.е. изначально 1024 элемента, после того, как исчерпали - увеличиваем на 1024 элемента.

Ещё более грамотным будет плавающее значение кванта в зависимости от размера структуры. Т.е.определить квант, например, в (4096 / sizoef элемента). В этом случае независимо от размера элемента у тебя память будет расходоваться кусками по 4096 байт (что составляет одну страницу памяти - система работает с такими же квантами). Но тут будут ньюансы: если размер элемента больше 4096 или когда 4096 нацело не делится. Тут надо более аккуратно работать, а потому такой вариант годится скорее для саморазвития, чем для сдачи задания (потому что чем сложнее реализация, тем больше можно наделать ошибок)
ForEveR
Модератор
Эксперт С++
 Аватар для ForEveR
7958 / 4720 / 319
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
20.05.2011, 16:57     realloc и вызов конструктора #18
Evg, Ну в STL множитель где-то 1.5 как пишет Саттер. Да и в MSVS реализации вектора было именно так.
pito211
 Аватар для pito211
186 / 173 / 8
Регистрация: 22.03.2010
Сообщений: 612
20.05.2011, 17:07  [ТС]     realloc и вызов конструктора #19
а лафоре хвалит коэффицент х2 в главе про класс алокатор

говорит удивительнорго эффективный
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.05.2011, 17:23     realloc и вызов конструктора
Еще ссылки по теме:

C++ Вызов копирующего конструктора
C++ Вызов конструктора
C++ Вызов конструктора копий
C++ Вызов конструктора класса
C++ Вызов конструктора с аргументами

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

Или воспользуйтесь поиском по форуму:
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
17192 / 5446 / 337
Регистрация: 30.03.2009
Сообщений: 14,794
Записей в блоге: 26
20.05.2011, 17:23     realloc и вызов конструктора #20
Цитата Сообщение от ForEveR Посмотреть сообщение
Evg, Ну в STL множитель где-то 1.5 как пишет Саттер
Цитата Сообщение от pito211 Посмотреть сообщение
говорит удивительнорго эффективный
По скорости работы - скорее всего будет эффективнее. По памяти - большой вопрос. Хотя в наши дни считается, что скорость важнее потребляемой памяти, потому что её много.

Реально конечно же всё зависит от конкретной задачи. Если один и тот же массив после заполнения постоянно очищается и перезаполняется - то ему пофиг, потому что память уже выделена и при освобождении массива память как правило НЕ отдаётся системе (т.е. при дальнейшем заполнении массива к сиситеме мы уже не бдем обрашщаться, т.к. память у нас есть). Если задача такая, что есть много массивов, но заполняются редко, то надо идти по пути экономии памяти, потому что в скорости от этого навара будет мало. Если массивы сильно заполняются, но живут недолго, то идти надо по пути максимальной скорости работы (потому что память быстро возвращается и её незачем сильно экономить). Собственно, потому и во всех контейнерах можно подсунуть свой аллокатор, который "знает", как работает твоя конкретная задача и наиболее оптимальным образом расходует память. А дефолтный аллокатор - это уже на усмотрение разработчиков. Видимо, как я писал выше, на сегодняшний день считается, что в дефолтном среднестатистическом случае экспотенциальный режим выгоднее
Yandex
Объявления
20.05.2011, 17:23     realloc и вызов конструктора
Ответ Создать тему
Опции темы

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