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

Как выглядит изнутри динамическое выделение объекта через new? - C++

Восстановить пароль Регистрация
 
mzarb
-211 / 7 / 1
Регистрация: 14.01.2013
Сообщений: 141
16.03.2013, 23:20     Как выглядит изнутри динамическое выделение объекта через new? #1
То есть на Си будет выглядеть так :
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
struct T
{
  int x, y;
};
 
/* Эта процедура является отображением конструктора T::T(int,int) */
void
T_constr (struct T *this, int _x, int _y)
{
  this->x = _x;
  this->y = _y;
}
 
/* Эта процедура является отображением деструктора T::~T() */
void
T_destr (struct T *this)
{
  this->x = 0;
  this->y = 0;
}
...
/* Указатель он и в Африке указатель*/
struct T *ta, *tb;
...
void
func1 (void)
{
  ...
  /* Оператор new одновременно выполняет две вещи:
   * выделение памяти и вызов конструктора */
  ta = (struct T*) malloc (sizeof (struct T));
  T_constr (ta, 10, 11);
  ...
  tb = (struct T*) malloc (sizeof (struct T));
  T_constr (tb, 20, 21);
  ...
}
 
void
func2 (void)
{
  ...
  /* Оператор delete также одновременно выполняет две вещи:
   * вызов деструктора и удаление памяти */
  T_destr (ta);
  free (ta);
  ...
  T_destr (tb);
  free (tb);
  ...
}
А на C++ так :
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
/* Описание класса такое же, как и в предыдущем примере.
 * Я повторяю его, чтобы не нарушить целостность примера. */
class T
{
  private:
    int x, y;
  public:
    T (int _x, int _y) { x = _x; y = _y; }
    /* Смысла в этом деструкторе нет, но пишу его в таком виде, чтобы он был не пустой */
    ~T () { x = 0; y = 0; }
}
...
/* Динамические объекты адресуются указателями и никак больше */
T *ta, *tb;
...
void
func1 (void)
{
  ...
  /* Создаём динамические объекты */
  ta = new T (10, 11);
  ...
  tb = new T (20, 21);
  ...
}
 
void
func2 (void)
{
  ...
  /* Удаляем динамические объекты */
  delete ta;
  ...
  delete tb;
  ...
}
Так вот в Си все понятно, то есть сначала выделяется память с помощью кода "ta = (struct T*) malloc (sizeof (struct T));" , а потом вызывается функция "T_constr" и принимает аргументом указатель на выделенную память. Получается две инструкции, выделения памяти и вызов функции констр.
А теперь вопрос, что происходит в C++? Этапы исполнения этого кода "ta = new T (10, 11);", в принципе знаю, то есть сначала new выделяет память и возвращает адрес, потом запускается конструктор и создает объект в этой памяти или точней инициализирует эту память, дальше указателю присваивается адрес этой памяти. Но как-то это все абстрактно, как это выглядит на самом деле? Допустим new вернула адрес, а что дальше, как выглядит запуск конструктора с этим адресом и как потом этот адрес присваивается указателю "ta" и как это вообще вмещается в одной инструкцие?
Пример кода был взят отсюда
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
16.03.2013, 23:20     Как выглядит изнутри динамическое выделение объекта через new?
Посмотрите здесь:

C++ Динамическое выделение
динамическое выделение C++
C++ динамическое выделение имен
Динамическое выделение памяти C++
C++ Динамическое выделение памяти
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
16.03.2013, 23:32     Как выглядит изнутри динамическое выделение объекта через new? #2
ну так как описано в си, так примерно и в с++ происходит. не без особенностей конечно, но примерно так же.
по поводу "вмещается в одной инструкции" - что тут удивительного.
C++
1
2
3
4
5
6
7
8
9
10
11
12
void f()
{
   // тут код порабощения мира
}
 
 
//в основной программе:
...
f(); // вроде простой вызов функции, но на самом деле происходит много чего.
     // так же и с new. букв мало, но встретив их компилятор много всяких ассемблерных команд
     // в конечном итоге навтыкает.
...
ValeryS
Модератор
6375 / 4841 / 443
Регистрация: 14.02.2011
Сообщений: 16,044
16.03.2013, 23:36     Как выглядит изнутри динамическое выделение объекта через new? #3
Цитата Сообщение от mzarb Посмотреть сообщение
Этапы исполнения этого кода "ta = new T (10, 11);", в принципе знаю, то есть сначала new выделяет память и возвращает адрес, потом запускается конструктор и создает объект в этой памяти или точней инициализирует эту память, дальше указателю присваивается адрес этой памяти. Но как-то это все абстрактно, как это выглядит на самом деле?
так и выглядит
поскольку в С++ нельзя вызвать конструктор напрямую то смоделировать ситуацию не удастся
могу порекомендовать скомпилировать простейшую программу и пройти отладчиком по шагам в режиме дизасемблера
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
16.03.2013, 23:48     Как выглядит изнутри динамическое выделение объекта через new? #4
Да, тут не все так просто. Следует разделять new как key word языка С++ и как void* operator new(std::size_t). Это не совсем одно и тоже.
Вот, что я видел в ассемблерном листинге в MSVS (возможно другой компилятор сделает по-другому) - сначала идет вызов operator new(std::size_t), потом вызывается конструктор класса (т.е. вызов конструтора происходит не в new, а после него, об этом заботится компилятор), которому передается адрес, который вернул new.
ValeryS
Модератор
6375 / 4841 / 443
Регистрация: 14.02.2011
Сообщений: 16,044
16.03.2013, 23:50     Как выглядит изнутри динамическое выделение объекта через new? #5
Цитата Сообщение от Kastaneda Посмотреть сообщение
void* operator new(std::size_t).
обычно это обертка над malloc( хотя у каждого может быть свое)
сейчас попробую скомпилить простейший пример и скинуть листинг, если это интересно
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4236 / 2769 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
16.03.2013, 23:57     Как выглядит изнутри динамическое выделение объекта через new? #6
Ну в cl.exe (MSVS) да, обертка над malloc(), при чем ситуация, когда malloc() возвращает 0, обрабатывается там же.
ValeryS
Модератор
6375 / 4841 / 443
Регистрация: 14.02.2011
Сообщений: 16,044
17.03.2013, 00:15     Как выглядит изнутри динамическое выделение объекта через new? #7
Цитата Сообщение от Kastaneda Посмотреть сообщение
Ну в cl.exe (MSVS) да, обертка над malloc(),
уже нет
меня послали к declspec(dllimport) void * __cdecl operator new(unsigned int)
который лежит в MSVCR90D.dll
правда я дебиг версию дизасемблил
сейчас попробую статически слинковать
да и
Цитата Сообщение от Kastaneda Посмотреть сообщение
при чем ситуация, когда malloc() возвращает 0, обрабатывается там же.
делается хитро
если не выделена память в указатель записывается 0
и при любом обращении вылетит исключение

Добавлено через 8 минут
а при статической линковке все таки malloc
mzarb
-211 / 7 / 1
Регистрация: 14.01.2013
Сообщений: 141
17.03.2013, 00:41  [ТС]     Как выглядит изнутри динамическое выделение объекта через new? #8
Цитата Сообщение от DU Посмотреть сообщение
ну так как описано в си, так примерно и в с++ происходит.
Хотелось бы точного представления.
Цитата Сообщение от DU Посмотреть сообщение
по поводу "вмещается в одной инструкции" - что тут удивительного.
Так конструктор запускает не внутри функции оператора new, а после него, то есть ваш пример уже не подходит, так как тут не понятно что происходит в одной инструкцие.
Цитата Сообщение от ValeryS Посмотреть сообщение
так и выглядит
поскольку в С++ нельзя вызвать конструктор напрямую то смоделировать ситуацию не удастся
То есть нужно смирится и максимум представлять что-то наподобие аналога на Си?

Цитата Сообщение от ValeryS Посмотреть сообщение
могу порекомендовать скомпилировать простейшую программу и пройти отладчиком по шагам в режиме дизасемблера
Почему-то в голове засела мысль, что возможно это объяснить и проиллюстрировать средствами C++, но так вы говорите что это невозможно, то теперь понятно почему меня закидали тапками на SO, когда попытался описать что происходить.
Цитата Сообщение от Kastaneda Посмотреть сообщение
Вот, что я видел в ассемблерном листинге в MSVS
Не думал, что для понимания работы таких вещей, понадобится другой яп. Но ладно, в будущем ещё доберусь до этой темы уже с асмом в арсенале.
ValeryS
Модератор
6375 / 4841 / 443
Регистрация: 14.02.2011
Сообщений: 16,044
17.03.2013, 00:57     Как выглядит изнутри динамическое выделение объекта через new? #9
Цитата Сообщение от mzarb Посмотреть сообщение
Но ладно, в будущем ещё доберусь до этой темы уже с асмом в арсенале.
да я тебе счас скину прокоментирую как смогу

Добавлено через 8 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;
class A
{
public:
    int a;
    A(){a=0;};
    virtual ~A(){};// виртуальность нужна чтобы вызвался конструктор, иначе оптимизатор может его выбросить 
};
 
 
//unsigned long int array[100000];
int main()
{
 A* a=new A;
 cout<<a->a;
 delete a;
 return 0;
}

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
              call    j_??2@YAPAXI@Z  ;      operator new(uint)вот вызывается new
.text:0043CD04                 add     esp, 4
.text:0043CD07                 mov     [ebp+this], eax; здесь записаваем в переменную
.text:0043CD0D                 mov     [ebp+var_4], 0
.text:0043CD14                 cmp     [ebp+this], 0 ; если new вернул ноль то идем к ветке где в указатель запишется 0
.text:0043CD1B                 jz      short loc_43CD30
.text:0043CD1D                 mov     ecx, [ebp+this] ; this
.text:0043CD23                 call    j_??0A@@QAE@XZ  ; A::A(void) ; иначе вызываем конструктор
.text:0043CD28                 mov     [ebp+var_10C], eax ; в указатель запишем экземпляр класса
.text:0043CD2E                 jmp     short loc_43CD3A
.text:0043CD30 ; ---------------------------------------------------------------------------
.text:0043CD30
.text:0043CD30 loc_43CD30:                             ; CODE XREF: _main+5Bj
.text:0043CD30                 mov     [ebp+var_10C], 0  ; вот здесь в указатель пишем 0 
                                                     ;это для того чтобы любое обращение вызвало исключение 
.text:0043CD3A
.text:0043CD3A loc_43CD3A:                             ; CODE XREF: _main+6Ej
.text:0043CD3A                 mov     eax, [ebp+var_10C]; вот здесь начинаем работать с классом
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
17.03.2013, 01:06     Как выглядит изнутри динамическое выделение объекта через new? #10
Цитата Сообщение от mzarb Посмотреть сообщение
Почему-то в голове засела мысль, что возможно это объяснить и проиллюстрировать средствами C++, но так вы говорите что это невозможно, то теперь понятно почему меня закидали тапками на SO, когда попытался описать что происходить.
Можно. malloc() + placement new. Это в точности то же, что делает обычный new. (За исключением обработки ошибок выделения памяти и прочих исключений.)
ValeryS
Модератор
6375 / 4841 / 443
Регистрация: 14.02.2011
Сообщений: 16,044
17.03.2013, 01:07     Как выглядит изнутри динамическое выделение объекта через new? #11
Цитата Сообщение от OhMyGodSoLong Посмотреть сообщение
Можно.
как ты покажешь вызов конструктора?
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
17.03.2013, 01:28     Как выглядит изнутри динамическое выделение объекта через new? #12
Placement new же. Он не выделяет память, только вызывает конструктор и подсовывает ему переданный this.

Добавлено через 5 минут
(Минорное исправление: не malloc(), а operator new() всё же, но не так важно.)
ValeryS
Модератор
6375 / 4841 / 443
Регистрация: 14.02.2011
Сообщений: 16,044
17.03.2013, 01:44     Как выглядит изнутри динамическое выделение объекта через new? #13
Цитата Сообщение от OhMyGodSoLong Посмотреть сообщение
Placement new же.
Буду знать
только посмотрев примеры никак не могу понять где это мне пригодится
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
17.03.2013, 02:27     Как выглядит изнутри динамическое выделение объекта через new? #14
Если не надо писать какой-то особый аллокатор памяти (memory pool, например), то нигде.
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
17.03.2013, 03:04     Как выглядит изнутри динамическое выделение объекта через new? #15
Разница зависит от высоты точки обзора.
Если с самой низкой высоты посмотреть (на ассемблерный код) - то разница определенно будет.
Если с самой высокой - то разницы нет. динамическое создание объекта состоит из двух шагов:
1 выделение памяти
2 инициализация байтов в этой выделенной памяти.

Рассмотрим с точки посередине:
Выделение памяти: в сях и в плюсах используются разные функции. в плюсах из функциии выделения памяти может вылететь исключение.

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

Ну и еще в плюсах отслеживается вылет исключения при конструировании и освобождается выделенная память в случае исключения.

Добавлено через 6 минут
на счет Placement new можно использовать для оптимизации, избавляясь от лишних вызовов выделения памяти если известен размер объектов. В классике создается массив чаров нужного размера. И объект конструируется в этом массиве. В векторе используется. Емкость вектора >= количеству элементов в векторе. По мере роста размера вектора, если есть зарезервированная память, то объекты создаются в ней. Иначе - перераспределение.
ValeryS
Модератор
6375 / 4841 / 443
Регистрация: 14.02.2011
Сообщений: 16,044
17.03.2013, 09:00     Как выглядит изнутри динамическое выделение объекта через new? #16
OhMyGodSoLong, хотя знаешь с точки зрения объяснения, как то но гуд
напишем (код из вики)
C++
1
2
3
4
5
A* placementMemory = static_cast<A*>(operator new[] (n * sizeof(A)));//выделим память
for (int i = 0; i < n; i++)
{
  new (placementMemory + i) A(rand()); //здесь память для объекта не выделяется, но инициализируется
}
и вместо ясной картины еще больше все запутали
mzarb
-211 / 7 / 1
Регистрация: 14.01.2013
Сообщений: 141
17.03.2013, 10:57  [ТС]     Как выглядит изнутри динамическое выделение объекта через new? #17
Цитата Сообщение от Kastaneda Посмотреть сообщение
Следует разделять new как key word языка С++ и как void* operator new(std::size_t).
То есть ключевое слово new берет на себя запуск функции оператора void* operator new(std::size_t) и потом запуск конструктора или оно заканчивает свое выполнение на возвращении адреса? И ещё это ключевое слово само делает sizeof для аргумента, который передастся в параметр size_t?
Цитата Сообщение от ValeryS Посмотреть сообщение
и вместо ясной картины еще больше все запутали
А компилятор в этом коде new (placementMemory + i) A(rand()); вернувшийся адрес от new передает сразу как this конструктору или подставляет там где точки A ... (rand()) ? И вообще почему A(rand()) не воспринимается компилятором как вызов функции, но воспринимается как создание объекта без имени? То есть он знает, что нельзя вызвать конструктор напрямую или смотрит по контексту какому-то?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.03.2013, 11:16     Как выглядит изнутри динамическое выделение объекта через new?
Еще ссылки по теме:

динамическое выделение памяти для объекта класса C++
C++ Как работает динамическое выделение памяти под объект?
C++ динамическое выделение памяти new

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

Или воспользуйтесь поиском по форуму:
ValeryS
Модератор
6375 / 4841 / 443
Регистрация: 14.02.2011
Сообщений: 16,044
17.03.2013, 11:16     Как выглядит изнутри динамическое выделение объекта через new? #18
Цитата Сообщение от ValeryS Посмотреть сообщение
A* placementMemory = static_cast<A*>(operator new[] (n * sizeof(A)));//выделим память
Вот здесь мы просто выделяем память под n объектов A указатель placementMemory указывает на выделенную память (аналог malloc())
Цитата Сообщение от ValeryS Посмотреть сообщение
new (placementMemory + i) A(rand())
а здесь вызываются конструкторы
видя в качестве аргумента указатель на память new не выделяет память а просто вызывает конструктор A(rand()
это и есть Placement new
вот есть статейка
http://itw66.ru/blog/c_plus_plus/471.html
Yandex
Объявления
17.03.2013, 11:16     Как выглядит изнутри динамическое выделение объекта через new?
Ответ Создать тему
Опции темы

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