Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Динамическое размещение объекта в определённом мес 
:(
    Опции темы
Compositum
  Дата 4.10.2013, 17:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Senior developer
**


Профиль
Группа: Awaiting Authorisation
Сообщений: 430
Регистрация: 6.1.2008
Где: Санкт-Петербург

Репутация: нет
Всего: 1



Доброго времени суток.

В C++ имеется возможность размещать объект по чётко определённому, указанному разработчиком, адресу в памяти. В свете этого у меня возник вопрос об освобождении памяти, использованной таким образом. 

Пусть, к примеру, у меня имеется некоторый массив объектов char (выделенный ранее динамически) и указывающий на адрес, по которому вдруг потребовалось разместить объект некоторого класса A. 

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

Интуитивно считаю, что в третьем варианте память должна освобождаться (деструктор там я вызываю вручную, иначе он не будет вызван). Оператору delete указываю "родной" указатель типа char, которому и была изначально выделена память. 

Но вот первый и второй вариант... С одной стороны, я использовал new, а с другой - я ведь не выделял новую память, а указал адрес уже выделенной ранее... Вот что в данном случае происходит? Происходит ли освобождение памяти, или же всё ограничивается банальным вызовом деструктора без последующего освобождения памяти? Как можно определить, произошло ли освобождение памяти? Может какой инструмент для этого имеется в GCC и MS Visual Studio 2012?

Код

#include <iostream>
#include <exception>
using namespace ::std;

class A{
private:
    double x;
public:
    A() : x(0) { cout << "A class; ptr: " << this << " created." << endl; }    
    ~A() { cout << "A class; ptr: " << this << " destroyed." << endl; }
};

int main(int argc, char* argv[])
try{    
    int x = -1; // Variants of memory clearing
    while (x < 0 || x > 2) {
        cout << "Variant (0,1,2): ";
        cin >> x;
    }
    char* p = new char[sizeof(A)]; // some memory area...
    
    A* a = new(p)A(); // Place my object in the 'p' address.
    
    // Here is my basic work to do...
    
    // Now I must to free my memory:
    if(!x){ // First variant
        delete a;            
    }
    else if (x == 1){ // Second variant
        delete reinterpret_cast<A*>(p);    
    }
    else if (x == 2){ // Third variant
        a->~A();        
        delete[] p;    
    }
    else{
        throw runtime_error("Invalid variant!");
    }
    a = nullptr;
    p = nullptr;
    
    cout << endl;    
}
catch(exception& e){
    cerr << e.what() << endl;
    return 1;
}
catch(...){
    cerr << "Unknown exception." << endl;
    return 2;
}


Спасибо.

Это сообщение отредактировал(а) Compositum - 4.10.2013, 17:55
PM   Вверх
volatile
Дата 4.10.2013, 18:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



третий вариант правильный.
первые два использовать нельзя.

т.е. если было так:
Цитата(Compositum @  4.10.2013,  17:54 Найти цитируемый пост)
   char* p = new char[sizeof(A)]; // some memory area...
    A* a = new(p)A(); // Place my object in the 'p' address.


то удалять нужно так:
Цитата(Compositum @  4.10.2013,  17:54 Найти цитируемый пост)
        a->~A();        
        delete[] p;


PM MAIL   Вверх
Compositum
Дата 4.10.2013, 18:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Senior developer
**


Профиль
Группа: Awaiting Authorisation
Сообщений: 430
Регистрация: 6.1.2008
Где: Санкт-Петербург

Репутация: нет
Всего: 1



Цитата(volatile @ 4.10.2013,  18:06)
первые два использовать нельзя.

А вот почему (хочу понять)? Ведь все указатели указывают на одну и ту же ячейку памяти и объект занимает столько же байт...
PM   Вверх
volatile
Дата 4.10.2013, 18:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Compositum, есть такая вещь как стандарт, там написано что можно и что нельзя.
а почему... это вопрос риторический.

дофига разных почему можно задать.
например почему нельзя сдвигать отрицательные числа? ну вот почему?!
нельзя. и пепец. все.

Потому-что разработчики компиляторов ориентируются на стандарт.
И если там написано что нельзя, то они это в праве и не реализовывать.

Добавлено через 1 минуту и 15 секунд
ну, может кто ответит более внятно..почему..

PM MAIL   Вверх
o2n3e
Дата 4.10.2013, 19:01 (ссылка)    | (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 19.8.2011

Репутация: -4
Всего: -5



Цитата

   В C++ имеется возможность размещать объект по чётко определённому, указанному разработчиком, адресу в памяти.
   

Не имеется. Вначале осиль указатели, перед тем, как задавать вопросы из ада. В твоём случае первая половина new(), а именно аллокатор заменяется на какой-нибудь cast(), а вторая его половина вызывает твои конструкторы и прочее.


Код

char * p = new char[sizeof(A)];
A * ptr = (A *)p;//как там у вас положенно писать касты я не знаю.
//тут new вызывает твой конструктор от A.



Это ничем не отличается от простого new. Деструктор не влияет на твой "объект", поэтому его один хрен надо удалять, либо юзай "стек".


Портянка твоя ужасна, бесполезна и мне даже лень её читать.




Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
o2n3e
Дата 5.10.2013, 21:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 19.8.2011

Репутация: -4
Всего: -5



Нет никаких нельзя - есть УБ и гарантии. Т.е. есть вещи, которые работают 100% так, а есть те, которые хрен знает как работают. Естественно реально никаких УБ нет и это всё отстранённая от реального мира брехня.


Те же сдвиги. Сдвигать можно всё - только за результат отвечает уже не стандарт, а знание матчасти. Если у тебя есть знаковые сдвиги, либо их софтварный аналог и ты знаешь что из себя представляют псевдознаковые числа - то сдвигать тебе их ничего не мешает. Формально да - это уб, но реально формат записи знака везде один, знаковые сдвиги есть много где, а если нет, то ~/конпелятор тебе в руки. И то, это даже не уб, а "результат немного не такой, как в учебнике".



Там не написанно "нельзя" - там написанно: "уб". Нет такой вещи в сишке, как "нельзя". Там нельзя максимум синтаксическое. А уб "разработчики конпелятора" в праве не не реализовывать, а реализовывать так, как хотят. Реально, если конечно конпелятор писали не адепты паскалятинки ака "динща из ада"(привет мелкософт), то реализацию у УБ всегда ~= одной. Хотя это больше не "днища из ада", а вендорлок.

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
o2n3e
Дата 5.10.2013, 22:11 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 19.8.2011

Репутация: -4
Всего: -5



Запомни раз и навсегда - кто тебе отвечает ответами вида: "стандарт", "уб", "потомучто" - дно из ада.


По поводу твоего вопроса - я тебе уже объяснил почему.


Код

#include <iostream>
#include <stdint.h>
#include <stdio.h>

using namespace std;

class A{
private:
    double x;
public:
    A() : x(0) { cout << "A class; ptr: " << this << " created." << endl; }    
    ~A() { cout << "A class; ptr: " << this << " destroyed." << endl; }
};

int main(int argc, char **argv) {
  char * p = new char[sizeof(A)]; // some memory area...
  fprintf(stderr, "%p\n", p);
  A * a = new(p)A(); // Place my object in the 'p' address.
  fprintf(stderr, "%p\n", a);
  delete a;
  p = new char[sizeof(A)];
  fprintf(stderr, "%p\n", p);
}


Это работает везде и будет работать. new/delete - банальная обвязка над маллоком, вернее оператор new/delete. Сам же new/delete просто вставляет конструктор/деструктор не более.


Аллокатор клал на твои классы/не классы. Вообще никаких классов нет. Поэтому похрен что ты там удаляешь, ибо оператор delete не знает тип. Узнаёт он его либо из иннода, который стоит левее от твоего указателя. *(uint64_t *)((uintptr_t)p - 16(8)). "Инноды" могут хранится вообще в другом месте, либо их может не быть, но в любой вменяемой реализации оператор delete будет класть на типы.


Но суть в том, что это поведение не определенно в стандарте - поэтому любой идиот может запилить так, что оператор delete будет зависить от типа и этому коду прийдёт конец( вернее конпеляция отвалится и у тебя бы этого вопроса не возникло). Хотя я даже не представляю зачем это надо и в чём будет профит. Это можно юзать для "быстрой" аллокации контантных величин, которые не будут задействовать райнтайм и все проверки делать в компилтайме.


Допустим, если у тебя есть "иннод" от твоего кусочка, то можно проверить релаьно ли он выделен, либо уже нет. Поэтому ты можешь хоть 100500 раз юзать delete, который при первом вызове затерёт иннод и дальше работать не будет. Сдесь же конпелятор должен будет чекать весь твой код. Причем работать будет лишь для локального мусора.


Т.е. delete p; реально работает и будет работать везде, но это уб и идиоты тебя за это не погладят.

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
volatile
Дата 6.10.2013, 02:27 (ссылка) |    (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(o2n3e @  5.10.2013,  22:11 Найти цитируемый пост)
Запомни раз и навсегда

имхо, новый троль какойто.
предвижу некоторое оживление форума..  smile 
интонации хороши.
научит щас всех уму разуму.

PM MAIL   Вверх
o2n3e
Дата 6.10.2013, 15:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 19.8.2011

Репутация: -4
Всего: -5



Новый тролль. В чём тролль? Давай, обоснуй мне попоцаночке.

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
akizelokro
Дата 6.10.2013, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Всё это глубоко индивидуально. Но уточню терминологию.
К примеру, старый стиль, ещё из Сишника вывода на экран в DOS-программах. Записываешь символы в определенную область памяти (с 0х8000 начинается чтоли, если мне моя память не изменяет) и ничего освобождать не надо. У тебя же не 
Цитата

размещать объект по чётко определённому, указанному разработчиком, адресу в памяти
,
а размещается объект в памяти, предварительно выделенной с помощью оператора new.

Дальше, останавливаться на том, что нежелательно ввод-вывод в потоки производить в деструкторе, думаю, не нужно.
Ну, и дальше малость посмотрел. Есть чистый ООП стиль (который ещё не отменил функцию malloc), есть стиль Сшных программистов (откуда функция malloc и появилась). ДУмаю, что незачем их смешивать, потому что из-за путаницы в стилях ухудшается внутренняя логика кода.

Это сообщение отредактировал(а) akizelokro - 6.10.2013, 16:58


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
o2n3e
Дата 6.10.2013, 18:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 19.8.2011

Репутация: -4
Всего: -5



DOS - это говнище из ада, которое к вопросу ниеимеет никакого отношение. Это мёртворождённое говно, которое было ущербно со дня своего появления и во время своей популярности, но почему-то было популярно.


Всё это - это аллокаторы и руление кучей - это всё абстракции рантайма и к памяти никакого отношения не имеют. Аллокаторы существуют только на уровне ОС и процессора, если ты юзаешь виртпамять.


У тебя же небыло кучи как таковой - у тебя банальная прямая адресация памяти, которая протухла лет 200назад.


Нет, никаких объектов нет, никакая память не выделяется, и никакйо new за неё не отвечает. new - это абстракция над рантайм кучей, которая к памяти отношения не имеет.


Есть стиль тех, кто понимает, что такое память, а есть тех, кто не понимает. Маллок - это студенческое говно, либо просто заюзанный для совместимости вызов в примитивном коде. Это не ООП стиль - это ООП кастыль, ибо new - это не только "аллокатор"(оператор new), а ключевое словое языка - как кой-нибудь return. Именно в этом и есть различие, а не в каких-то там стилях. А оператор new - это банальная обвязка над маллоком почти во всех либс++.


Никакой путаницы нет. Никакая логина не ухудшается, ибо просто конструкторы/деструкторы не вызваются. А поверье "юзай new/delete" - пошла потому, что тупая животные не могли запомнить простую вещь: "маллок для стандартных тимов, new для классов с конструкторами". И лепили маллок где попало.

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
EgoBrain
Дата 7.10.2013, 04:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 537
Регистрация: 23.3.2008
Где: Комната

Репутация: нет
Всего: 2



Цитата(volatile @  6.10.2013,  02:27 Найти цитируемый пост)
имхо, новый троль какойто.
предвижу некоторое оживление форума..  smile 
интонации хороши.
научит щас всех уму разуму.


volatile, мне твоя позиция немного непонятна. Троль как то убедительно вещает, особенно для незнающего читателя. Надеюсь местные авторитеты если нужно где-то подправят его.
PM MAIL ICQ Skype   Вверх
o2n3e
Дата 7.10.2013, 10:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 19.8.2011

Репутация: -4
Всего: -5



Тут нет таких авторитетов, котоыре осмеляться править меня - максимум они будут защищать свою шкурку от моей ненависти к досу и программистам не знающих матчасть, но называющих себя программистами.


Я вообе не понимаю, но юзал ты дос - посмейся нам этим и забудь как страшный сон, это как с паскалятинкой. Забудь и посмейся, аля: "был идиотом - бывает". Нет жешь они будут это говно защищать только лишь потому, чтобы о них не подумали, что они юзали говно.



Если я раньше юзал плюсы, то я забыл это как страшный сон. И согласен, что был дураком.

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
baldina
Дата 7.10.2013, 10:53 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



троля-ля...

EgoBrain, а его почти негде править, все правильно сказал. хитрость заключается в тонкой границе между техникой и методологией: технически правильные и работающие вещи могут быть ужасными с точки зрения ремонта и прочего сопровождения. крутизна не в том, что оно работает, а что всем понятно - как.
PM MAIL   Вверх
xvr
Дата 7.10.2013, 15:04 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(Compositum @  4.10.2013,  18:10 Найти цитируемый пост)
А вот почему (хочу понять)? Ведь все указатели указывают на одну и ту же ячейку памяти и объект занимает столько же байт... 

Потому что new/delete это не только malloc/free, но и вызов конкретных коснрукторов/деструкторов. И если для malloc/free важен только кусок памяти, с которым их попросили поработать, то для конструкторв/деструкторов важен ТИП того, что в этой памяти лежит. 1й и 2й вариант дают неправильную информацию о типе.

И вообще - удалением памяти должен заниматься тот, кто ее выделял. Placement new не выделяет память (он использует готовую), это значит, что вызывать обычный delete на этот участок памяти нельзя.

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0972 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.