Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > локальный сборщик мусора


Автор: Леопольд 29.6.2009, 20:12
Локальный сборщик мусора. Подчищает "хвосты" во время саморазрушения. Безопасен при исключениях. Покритикуйте пожалуйста, только без грубостей, я нежный... smile

30.06.2009. Переписал. Интерфейс немного изменился.
Код
#ifndef GARBAGECOLLECTOR
#define GARBAGECOLLECTOR

#include <new>
#include <cstdlib>

namespace garbage{

  class garbage{
  private:
    garbage *prev;
    garbage& operator=(const garbage&);
    garbage(const garbage&);
  public:
    void set_tail(garbage * const ptr){
      prev = ptr;
    }

    garbage(void){}
    virtual ~garbage(){ if(prev) delete prev;}
  };

  template<class T, class DelPolitic>
    class auto_delete: public garbage{
    private:
      auto_delete(const auto_delete&);
      auto_delete& operator=(const auto_delete&);
      T* pimpl;
    public:
      auto_delete(T* ptr):pimpl(ptr){
      }
      ~auto_delete(){
        DelPolitic::clear(pimpl);
      }
    };

  class del_single{
  public:
  template<class T>
    static void clear(T* ptr){
      delete ptr;
    }
  };
  class del_array{
  public:
  template<class T>
    static void clear(T* ptr){
      delete[] ptr;
    }
  };
  class free_c{
  public:
  template<class T>
    static void clear(T* ptr){
      free(ptr);
    }
  };

  class collector{
  private:
    collector(const collector&);
    collector& operator=(const collector&);
    garbage * head;
  public:
    collector(void):head(0){}
    template<class DelPolitic, class T>
      T* push(T* ptr) throw(std::bad_alloc){
        if(!ptr) throw std::bad_alloc();
        garbage *pushed = static_cast<garbage*>(new auto_delete<T,DelPolitic>(ptr));
        pushed->set_tail(head);
        head = pushed;
        return ptr;
      }
    ~collector(){
      if(head) delete head;
    }
  };

}//    end namespace garbage
#endif

Автор: andrew_121 29.6.2009, 20:13
Цитата(Леопольд @  29.6.2009,  20:12 Найти цитируемый пост)
я нежный...

тьфу!

Автор: Леопольд 29.6.2009, 20:18
Пример использования:
Код

#include <iostream>
#include <cstdlib>
#include "garbage_collector.hpp"

class Class{
public:
    ~Class(){
        std::cout<<"Class has been destroyed"<<std::endl;
    }
};
struct Struct{
public:
    ~Struct(){
        std::cout<<"Struct has been destroyed"<<std::endl;
    }
};


class free_c{
public:
template<class T>
    static void clear(T* ptr){
        free(ptr);
        std::cout<<"free has been performed"<<std::endl;
    }
};
int main(int argc, char* argv[])
{
        garbage::collector man;
        Class* ptrC = man.push<garbage::del_single>(new Class);
        Struct* ptrS = man.push<garbage::del_array>(new Struct[4]);
        int* ptri = man.push<free_c>((int*)malloc(sizeof(int)));
}


Добавлено @ 20:18
Цитата(andrew_121 @ 29.6.2009,  20:13)
Цитата(Леопольд @  29.6.2009,  20:12 Найти цитируемый пост)
я нежный...

тьфу!

очень конструктивно...

Автор: andrew_121 29.6.2009, 20:30
Цитата(Леопольд @  29.6.2009,  20:18 Найти цитируемый пост)
очень конструктивно...

Прошу прощения. Это не о коде!
Это реакция о том, что я процитировал.
Опять же, прошу прощения за оффтоп.

Мое почтение!

Автор: Леопольд 29.6.2009, 20:32
Цитата(andrew_121 @ 29.6.2009,  20:30)
...
Мое почтение!

Блаженно улыбаюсь smile

Автор: zim22 29.6.2009, 20:38
Цитата(Леопольд @  29.6.2009,  20:18 Найти цитируемый пост)

Код

int main(int argc, char* argv[]){    
  collector man;    
  man.push<del_single>(new TestClass1);   
   man.push<del_array>(new TestClass2[4]);
}

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

Автор: Леопольд 29.6.2009, 20:49
Цитата(zim22 @ 29.6.2009,  20:38)
неудобно использовать. коллектор надо создавать. потом вызывать его метод. передавать аргументы в шаблон...
нельзя оформить это в виде шаблонной функции со статическим хранилищем?

Если не создавать, то как разрушать автоматически, например, при порождении исключения?

Автор: zim22 29.6.2009, 20:55
Цитата(Леопольд @  29.6.2009,  20:49 Найти цитируемый пост)
Если не создавать, то как вызвать деструктор несозданного объекта?

никак. деструктор вызывается автоматически. хотя можно и явно его вызвать smile

вы хотели расширить auto_ptr, чтобы он мог корректно работать с массивами?
имхо, лучше отдельный класс написать тогда:
Код

template<typename T> class auto_array {
    T* res;
public:
    explicit auto_array(T* ptr) : res(ptr) {}
    ~auto_array() { if (res) delete[] res); }
    T* get() { return res; }
};

http://www.research.att.com/~bs/bs_faq2.html#auto_ptr Страуструп объясняет, почему не нужен auto_array
Цитата

A better solution is to use a vector

***
я попробовал с помощью функций реализовать, но не получилось smile
т.к. я объекты храню как указатели на void*, а при удалении необходимо void* преобразовать к типу...
Код

#include <stdexcept>
#include <iostream>

// тестовый класс для хранения в глобальном массиве объектов
class C { 
public:
  C()  { std::cout << "C\n"; }  
  void fcn() { }
  ~C() { std::cout << "~C\n"; }
};

namespace {
  const int max_num_of_objects = 100;
  void *object_list[max_num_of_objects] = {0}; // глобальное хранилище объектов
  static int object_count = 0;
}

// сохранить указатель на объект в хранилище
template <typename T>
T *store_array(T *ptr) {  
  object_list[object_count++] = ptr;
  return ptr;
}

// вызвать delete для указателя и удалить ссылку на него из хранилища
template <typename T>
void free_array(T *ptr) {
  for (int i = 0; i < max_num_of_objects; i++) {
    if (object_list[i] == ptr) {
      object_list[i] = 0;
      delete [] ptr;
    }
  }
}

// удалить все объекты, на которые есть указатели
void collect_garbage() {
  for (int i = 0; i < max_num_of_objects; i++) {
    if (object_list[i] != 0) {
      delete [] object_list[i]; // не работает :)
      object_list[i] = 0;
    }
  }
}

// тестовая функция
void fcn() {
  C *ptr = store_array(new C[3]);
  (ptr + 2)->fcn();
  throw std::exception("yo");
  free_array(ptr);
}
int _tmain(int argc, _TCHAR* argv[])
{    
  try {
    fcn();
  } catch (...) {
    collect_garbage();
  }
    return 0;
}

Автор: ЗапаснойЛеопольд 29.6.2009, 22:01
Цитата(zim22 @ 29.6.2009,  20:55)
вы хотели расширить auto_ptr, чтобы он мог корректно работать с массивами?

Неа, мне было интересно сделать  примитивный сборщик мусора для объектов произвольного типа и размерности, который, при этом правильно их уничтожает. auto_array не предназначен для этого. Моя штуковина намного гибче smile Можно задавать свою политику очистки памяти.

пример:
Код

template<class T>
    class free_c{
    public:
        static void clear(T* ptr){
            free(ptr);
            std::cout<<"free has been performed"<<std::endl;
        }
    };
int main(int argc, char* argv[])
{
    garbage::collector man;
    man.push<garbage::del_single>(new Class);
    man.push<garbage::del_array>(new Struct[4]);
    man.push<free_c>((int*)malloc(sizeof(int)));
}



По какой-то причине я не могу постить под моим основным аккаунтом на форуме до завтрашнего вечера. Я что-то нарушил?

Автор: ЗапаснойЛеопольд 29.6.2009, 22:36
Цитата(zim22 @ 29.6.2009,  20:38)
неудобно использовать....передавать аргументы в шаблон...

В шаблоне передается шаблон smile Я не знаю, как можно сделать удобнее не потеряв масштабируемость. Есть идеи?

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

Можно усовершенстовть так, чтобы контейнер тоже задавался в виде шаблонного параметра. У меня не получилось сделать с аргументом шаблона по умолчанию, STL контейнеры имеют свои шаблонные параметры по умолчанию, а я не помню как это побороть.
Код

    template<template<class T> class Container = std::list>
        class collector{
        private:
            typedef auto_delete<void,del_dummy> garbage;

            collector(const collector&);
            collector& operator=(const collector&);
            Container<garbage> collection;

Автор: andrew_121 29.6.2009, 22:51
ЗапаснойЛеопольд, Классный ник! smile 

Автор: Lazin 29.6.2009, 22:57
Цитата(ЗапаснойЛеопольд @  29.6.2009,  22:36 Найти цитируемый пост)
В шаблоне передается шаблон  Я не знаю, как можно сделать удобнее не потеряв масштабируемость. Есть идеи?

можно передавать в качестве шаблонного параметра структуру, внутри которой будет шаблон

Код

struct foo
{
     template<class T> struct bar {};
};

template<class T, class Policy>
struct MyClass
{
    typedef Policy:: template bar<T> my_policy;
};


только я не очень понимаю, чем этот класс лучше обычного scoped_ptr?

Автор: ЗапаснойЛеопольд 29.6.2009, 22:58
Цитата(andrew_121 @ 29.6.2009,  22:51)
ЗапаснойЛеопольд, Классный ник! smile

Сам придумал!!! smile

Добавлено @ 23:04
Цитата(Lazin @ 29.6.2009,  22:57)
только я не очень понимаю, чем этот класс лучше обычного scoped_ptr?

Ничем. Даже хуже из-за необходимости держать всё в одном контейнере. Причём всегда с виртуальным деструктором. Просто интересная головоломка... Хотя, если scoped_ptr не позволяет задавать кустарную очистку памяти (в чём я сомневаюсь)... но мне сейчас поздно лезть в boost.org , спать пора...

Код

man.push<del_single>(new ЛюбаяФигня);
man.push<clear_by_веник>(allocate_by_magic(НевообразимоКрутойКласс));

Но ведь красиво! smile

Добавлено @ 23:09
Цитата(Lazin @ 29.6.2009,  22:57)
Цитата(ЗапаснойЛеопольд @  29.6.2009,  22:36 Найти цитируемый пост)
В шаблоне передается шаблон  Я не знаю, как можно сделать удобнее не потеряв масштабируемость. Есть идеи?

можно передавать в качестве шаблонного параметра структуру, внутри которой будет шаблон

Не понял. Чем это удобнее чем man.push<garbage::del_array>(new int[10])?  smile Буду благодарен за пример...

Автор: DrHex 30.6.2009, 00:53
Зачем вообще collector? Деструктор не годится?(collector только добовляет накладные ресурсы)


Автор: Lazin 30.6.2009, 05:51
Цитата(ЗапаснойЛеопольд @  29.6.2009,  22:58 Найти цитируемый пост)
Не понял. Чем это удобнее чем man.push<garbage::del_array>(new int[10])?   Буду благодарен за пример...

ты же попросил пример smile 
вообще, вариант, который я предложил применяется в boost.mpl, лучше он тем, что обычные шаблонные параметры проще использовать, расширяемость лучше итд...
можно еще использовать идиому traits

Код

struct del_traits
{
somewhat...
};

template<class T>
void push(T* t)
{
    typedef del_traits<T> traits;
    somewhat...
}

в этом случае тебе не нужно будет явно указывать garbage::del_array для каждого вызова, вместо этого ты можешь специализировать класс del_traits, для своего типа, и он будет использоваться в методе push 

Автор: Леопольд 30.6.2009, 22:49
Цитата(Lazin @ 30.6.2009,  05:51)
Цитата(ЗапаснойЛеопольд @  29.6.2009,  22:58 Найти цитируемый пост)
Не понял. Чем это удобнее чем man.push<garbage::del_array>(new int[10])?   Буду благодарен за пример...

ты же попросил пример smile 

Я имел ввиду пример использования. smile

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

Я не знаю как можно придумать удобнее, сохранив при этом обобщённость:
============================================================================================
garbage::collector cleaner;

...
AnyType* ptr = cleaner.push<garbage::del_single>(new AnyType);
...
AnotherType* array = cleaner.push<garbage::del_array>(new AnotherType[size]);
...
SpecialType* something = cleaner.push<special_clean_array>(special_alloc(SpecialType));
============================================================================================
Если есть идеи, как можно упростить это или сделать более наглядным, буду благодарен... smile

Добавлено @ 22:55
Цитата(Lazin @ 30.6.2009,  05:51)
можно еще использовать идиому traits
...
в этом случае тебе не нужно будет явно указывать garbage::del_array для каждого вызова, вместо этого ты можешь специализировать класс del_traits, для своего типа, и он будет использоваться в методе push

traits не подходит по той причине что я могу захотеть удалять указатель на один и тот же тип разными способами.

Т.е.
int* ptr = cleaner.push<garbage::del_single>(new int);
int* array = cleaner.push<garbage::del_array>(new int[size]);

Добавлено @ 22:59
Я переписал утилитку, gcc не хотел собирать (новая версия в первом посте). Получилось даже лучше. Я так же изменил способ хранения указателей на объекты на максимально лёгкий, какой смог придумать. Теперь сборщик уступает scoped_array (для целей локальной автоуборки) только виртуальными вызовами деструкторов. Это плата за универсальность. Хотя, было бы неплохо от этого избавиться. Но как это сделать не меняя способа использования, я не знаю.

Автор: Леопольд 30.6.2009, 23:11
Цитата(DrHex @ 30.6.2009,  00:53)
Зачем вообще collector? Деструктор не годится?(collector только добовляет накладные ресурсы)

Можно поподробнее? Ничего же не понятно...

Автор: mes 1.7.2009, 01:32
мне вот прежде всего непонятно, зачем нужен такой контейнер, да еще и локальный.
не проще ли было бы просто пользовать обертку для каждого объекта отдельно ?

Автор: Lazin 1.7.2009, 08:42
Цитата(Леопольд @  30.6.2009,  22:49 Найти цитируемый пост)
Я не знаю как можно придумать удобнее, сохранив при этом обобщённость

так у тебя там и нет особой обобщенности, все довольно жестко задается на этапе компиляции...
например, у меня есть класс - пулл объектов, в котором я выделяю память, допустим, для удаления объекта, нужно вызывать метод free пулла, и передать в него указатель на объект, который нужно удалить.. допустим, в программе может быть несколько таких пуллов
в этом случае, твой deleter должен получать ссылку или указатель на пул объектов, из которого нужно этот объект потом удалить, с твоим кодом это сделать не получится, следовательно он не гибок smile 

Цитата(Леопольд @  30.6.2009,  22:49 Найти цитируемый пост)
Если есть идеи, как можно упростить это или сделать более наглядным, буду благодарен...
во первых, ты объединяешь множество не связанных операций в одну операцию, это уже не правильно
во вторых, у тебя объекты могут удалятся в произвольном порядке, это зависит от того, как их добавлять, если порядок удаления важен, то это может вызвать сложности

Цитата(Леопольд @  30.6.2009,  22:49 Найти цитируемый пост)
traits не подходит по той причине что я могу захотеть удалять указатель на один и тот же тип разными способами.

Т.е.
int* ptr = cleaner.push<garbage::del_single>(new int);
int* array = cleaner.push<garbage::del_array>(new int[size]);

это уже извращение, для массивов есть vector smile 
к тому-же, если у тебя объект одного типа удаляется несколькими разными способами, то это уже ошибка, лучше всего делать так, что-бы можно было на этапе компиляции однозначно определить как удалять объект, к примеру, если у тебя есть класс Foo, и он может быть создан в куче или с помощью специализированного менеджера памяти(и удаляться с помощью него), то во втором случае, лучше использовать какой-нибудь смарт поинтер вместо обычного указателя, что-бы можно было определить на этапе компиляции, как удалять объект. smile 
я сделал-бы это так:
Код

template<class T>
struct scoped_delete_base
{
    virtual void operator ()(T* t) = 0;
};

template<class T>
struct scoped_ptr_impl : scoped_delete_base<T>
{
    void operator ()(T* t)
    {
        delete t;
    }
};

template<class T>
struct scoped_array_impl : scoped_delete_base<T>
{
    void operator ()(T* t)
    {
        delete [] t;
    }
};

template<class T, class F>
struct scoped_func_impl : scoped_delete_base<T>
{
    F f;
    scoped_func_impl(F f)
        : f(f)
    {
    }
    
    void operator ()(T* t)
    {
        f(t);
    }
};

template<class T>
class scoped_ptr
{
    T* ptr_;
    scoped_delete_base<T>* impl_;
public:
    scoped_ptr(T* t)
        : ptr_(t)
        , impl_(new scoped_ptr_impl<T>()) //обычное удаление
    {
    }

    template<class F>
    scoped_ptr(T* t, F f)
        : ptr_(t)
        , impl_(new scoped_func_impl<T, F>(f))//удаление с помощью функтора
    {
    }
    
    ~scoped_ptr()
    {
        (*impl_)(ptr_);
        delete impl_;
    }
};

template<class T>
class scoped_array
{

    T* ptr_;
    scoped_delete_base<T>* impl_;
public:
    scoped_array(T* t)
        : ptr_(t)
        , impl_(new scoped_array_impl<T>()) //обычное удаление
    {
    }

    template<class F>
    scoped_array(T* t, F f)
        : ptr_(t)
        , impl_(new scoped_func_impl<T, F>(f))//удаление с помощью функтора
    {
    }
    
    ~scoped_array()
    {
        (*impl_)(ptr_);
        delete [] impl_;
    }
};

ничего не напоминает? smile 

Автор: ЗапаснойЛеопольд 1.7.2009, 09:11
Цитата(Lazin @ 1.7.2009,  08:42)
Цитата(Леопольд @  30.6.2009,  22:49 Найти цитируемый пост)
Если есть идеи, как можно упростить это или сделать более наглядным, буду благодарен...
во первых, ты объединяешь множество не связанных операций в одну операцию, это уже не правильно
во вторых, у тебя объекты могут удалятся в произвольном порядке, это зависит от того, как их добавлять, если порядок удаления важен, то это может вызвать сложности

каких именно несвязанных операций и почему они несвязанные?
объекты удаляются в порядке обратном созданию.

Автор: Леопольд 1.7.2009, 09:16
Цитата(Lazin @ 1.7.2009,  08:42)
Цитата(Леопольд @  30.6.2009,  22:49 Найти цитируемый пост)
traits не подходит по той причине что я могу захотеть удалять указатель на один и тот же тип разными способами.

Т.е.
int* ptr = cleaner.push<garbage::del_single>(new int);
int* array = cleaner.push<garbage::del_array>(new int[size]);

это уже извращение, для массивов есть vector smile 

Вот ещё одно извращение smile
Код

int* ptri = cleaner.push<garbage::free_c>((int*)malloc(sizeof(int)));


Добавлено через 1 минуту и 56 секунд
Цитата(Lazin @ 1.7.2009,  08:42)
Цитата(Леопольд @  30.6.2009,  22:49 Найти цитируемый пост)
Я не знаю как можно придумать удобнее, сохранив при этом обобщённость

так у тебя там и нет особой обобщенности, все довольно жестко задается на этапе компиляции...
например, у меня есть класс - пулл объектов, в котором я выделяю память, допустим, для удаления объекта, нужно вызывать метод free пулла, и передать в него указатель на объект, который нужно удалить.. допустим, в программе может быть несколько таких пуллов
в этом случае, твой deleter должен получать ссылку или указатель на пул объектов, из которого нужно этот объект потом удалить, с твоим кодом это сделать не получится, следовательно он не гибок smile

Напиши пожалуйста интерфейс пула, а я попытаюсь им воспользоваться...

Автор: Lazin 1.7.2009, 09:22
они удаляются в порядке, обратном вызовам ф-ии push smile 
если у меня есть объекты А и Б и я хочу, что-бы они были удалены после выхода из scope, то зачем-то создается список, в котором лежат указатели на А и Б(это как минимум два выделения памяти в куче), хотя достаточно пары стековых объектов?
почему удаление объектов А и Б должно для меня выглядеть как одна операция, хотя это 2 операции не связанные между собой? smile

Добавлено через 5 минут и 10 секунд
Цитата(Леопольд @  1.7.2009,  09:16 Найти цитируемый пост)
Напиши пожалуйста интерфейс пула, а я попытаюсь им воспользоваться...


Код

template<class T>
class ObjectPool
{
public:
    T* create();
    void free(T* p);
};


создание
Код

ObjectPool<Foo> pool;

Foo* f = pool.create();


удаление

Код

pool.free(f);


Код

collector.push<WTF?? адрес pool не известен на этапе компиляции!!>(f);

Автор: Леопольд 1.7.2009, 09:28
Цитата(Lazin @ 1.7.2009,  08:42)
к тому-же, если у тебя объект одного типа удаляется несколькими разными способами, то это уже ошибка, лучше всего делать так, что-бы можно было на этапе компиляции однозначно определить как удалять объект

Т.е. получается что С++ изначально имеет изъян, потому что позволят это делать... smile Почему ты считаешь что между типом объекта и способом выделения и освобождения памяти должна быть настолько жёсткая связь? Если это идиома, или code rule, то объясни, пожалуйста, её выгоды.

Автор: Lazin 1.7.2009, 09:38
Цитата(Леопольд @  1.7.2009,  09:28 Найти цитируемый пост)
Почему ты считаешь что между типом объекта и способом выделения и освобождения памяти должна быть настолько жёсткая связь?

А разве это не так? Если у тебя объект Foo* можно удалить 2мя способами, то как черт возьми я могу понять, глядя на этот указатель, как мне его удалить, не проследив его жизненный путь до момента создания? Ты хотел-бы разбираться потом в таком коде? Я - нет.

Автор: mes 1.7.2009, 10:07
Цитата
к тому-же, если у тебя объект одного типа удаляется несколькими разными способами, то это уже ошибка, лучше всего делать так, что-бы можно было на этапе компиляции однозначно определить как удалять объект

не согласен

Цитата(Lazin @  1.7.2009,  08:38 Найти цитируемый пост)
Если у тебя объект Foo* можно удалить 2мя способами, то как черт возьми я могу понять, глядя на этот указатель, как мне его удалить, не проследив его жизненный путь до момента создания?

Лучше предъявить требование, чтоб создание  и удаление были в "пределах видимости" программиста, что в принципе соблюдается у Леопольда:
Цитата(Леопольд @  1.7.2009,  08:16 Найти цитируемый пост)
 cleaner.push<garbage::free_c>((int*)malloc(sizeof(int)));

операция удаления "выбрана" рядом с операцией создания.


Леопольд, но все же зачем
Цитата(mes @  1.7.2009,  00:32 Найти цитируемый пост)
нужен такой контейнер, да еще и локальный?
не проще ли было бы просто пользoвать обертку для каждого объекта отдельно ?

тоесть вместо garbage_container ипользовать garbage_object.

Автор: Lazin 1.7.2009, 10:19
Цитата(mes @  1.7.2009,  10:07 Найти цитируемый пост)
операция удаления "выбрана" рядом с операцией создания.

никто не мешает мне передать в метод push что угодно smile 
Цитата(mes @  1.7.2009,  10:07 Найти цитируемый пост)
не согласен

мотивируй

Автор: mes 1.7.2009, 12:07
Цитата(Lazin @  1.7.2009,  09:19 Найти цитируемый пост)
никто не мешает мне передать в метод push что угодно smile 

с этим согласен, но это решается путем объеденения создания/удаления в один аллокатор.
и если избавиться от контейнера, то интерфейс создания объекта будет такой
Код

garbage_object<TObject, new_delete_alloc> object; 

где в принципе этот аллокатор можно поставить по умолчанию:
Код

garbage_object<TObject> object; 



Цитата(Lazin @  1.7.2009,  09:19 Найти цитируемый пост)

к тому-же, если у тебя объект одного типа удаляется несколькими разными способами, то это уже ошибка, лучше всего делать так, что-бы можно было на этапе компиляции однозначно определить как удалять объект
Цитата

не согласен

мотивируй 

Объекту не желательно знать о способе своего создания и хранения. Для этого есть врапперы (такие как умные указатели) которые задают нужную политику.




Автор: Lazin 1.7.2009, 12:58
Цитата(mes @  1.7.2009,  12:07 Найти цитируемый пост)
Объекту не желательно знать о способе своего создания и хранения. Для этого есть врапперы (такие как умные указатели) которые задают нужную политику.


Цитата(Lazin @  1.7.2009,  08:42 Найти цитируемый пост)
лучше использовать какой-нибудь смарт поинтер вместо обычного указателя, что-бы можно было определить на этапе компиляции, как удалять объект


я именно об этом и говорил

Автор: mes 1.7.2009, 13:36
Цитата(Lazin @  1.7.2009,  11:58 Найти цитируемый пост)
я именно об этом и говорил 

 smile 

Цитата(Леопольд @  1.7.2009,  08:28 Найти цитируемый пост)
Т.е. получается что С++ изначально имеет изъян, потому что позволят это делать... 

Cpp позволяет очень многое(и именно с этим связаны многие трудности с его освоением), но это не является изъяном.
Просто он (cpp) полагается на то, что свобода выражения превыше жестких рамок. 

Автор: Lazin 1.7.2009, 13:38
кстати, стоит отметить, что сабж - вовсе не сборщик мусора smile 

Автор: Леопольд 1.7.2009, 17:47
Цитата(Lazin @ 1.7.2009,  13:38)
кстати, стоит отметить, что сабж - вовсе не сборщик мусора smile

Пожалуй да. Но как то его обозвать надо было. Вот я и обозвал, что первое в голову пришло... smile
Пока не думал как можно было-бы заюзать его с пулом, некогда было. Возможно, для этого придётся что-нибудь изменить.
Однако если пул singleton, тогда можно будет написать политику удаления и так.

Добавлено @ 17:53
Цитата(Lazin @ 1.7.2009,  12:58)
Цитата(mes @  1.7.2009,  12:07 Найти цитируемый пост)
Объекту не желательно знать о способе своего создания и хранения. Для этого есть врапперы (такие как умные указатели) которые задают нужную политику.


Цитата(Lazin @  1.7.2009,  08:42 Найти цитируемый пост)
лучше использовать какой-нибудь смарт поинтер вместо обычного указателя, что-бы можно было определить на этапе компиляции, как удалять объект


я именно об этом и говорил

А я имел ввиду совсем другое.
Какие выгоды от того что способ выделения памяти напрямую зависит от типа? Чем плохо выделять int и при помощи new, и при помощи malloc? Или пользовательский тип? Может мне надо использовать специфический тип, для которого я не хочу вызывать конструктор и деструктор, например.

Автор: Леопольд 1.7.2009, 18:06
Цитата(mes @ 1.7.2009,  10:07)
Леопольд, но все же зачем
Цитата(mes @  1.7.2009,  00:32 Найти цитируемый пост)
нужен такой контейнер, да еще и локальный?
не проще ли было бы просто пользoвать обертку для каждого объекта отдельно ?

тоесть вместо garbage_container ипользовать garbage_object.

Я убрал вчера контейнер и сделал из объектов стек. Каждый объект удаляет предыдущий. Получается на один указатель больше чем без него, потому что надо хранить указатель на последний добавленный объект. Плюс ещё указатели на память. Недостаток в виртуальном деструкторе. Я вчера прогнал через профайлер. Больше всего времени уходит на вызов виртуального деструктора.
Вообще, можно ускорить процесс, если сделать отдельный pool для указателей а не выделять для каждого указателя новый кусочек каждый раз.
Но мне не хочется, потому что эта штука мне уже не нравится smile

Добавлено @ 18:12
Цитата(Lazin @ 1.7.2009,  10:19)
Цитата(mes @  1.7.2009,  10:07 Найти цитируемый пост)
операция удаления "выбрана" рядом с операцией создания.

никто не мешает мне передать в метод push что угодно smile 

И ничего удивительного. Даже константность можно снять приведением типов. Это С++.
Код

Foo* ptr = (Foo*)malloc(sizeof(Foo));
boost::shared_ptr<Foo>(ptr);

Даже если привязать способ очистки памяти к типу объекта при помощи traits, то что сможет помешать выделить память иначе для этого же объекта? Например, при помощи malloc... Тут уже всё зависит от программиста.

Но можно привязать способ очистки к способу выделения памяти а не к типу объекта. Я полагаю, mes, имел ввиду именно это.

Автор: mes 1.7.2009, 20:20
Цитата(Леопольд @  1.7.2009,  17:06 Найти цитируемый пост)
Я убрал вчера контейнер и сделал из объектов стек. Каждый объект удаляет предыдущий.

Позвольте узнать зачем ? а также хотелось бы услышать какую задачу должен решать Ваш компонент ? (а то обсуждаем зверя о сути которого нам практически ничего неизвестно smile )

Цитата(Леопольд @  1.7.2009,  17:06 Найти цитируемый пост)
Больше всего времени уходит на вызов виртуального деструктора.

А зачем Вам вообще обязательный виртуальный деструктор ? 

Цитата(Леопольд @  1.7.2009,  17:06 Найти цитируемый пост)
Цитата(Леопольд @  1.7.2009,  17:06 Найти цитируемый пост)
никто не мешает мне передать в метод push что угодно smile 

И ничего удивительного. Даже константность можно снять приведением типов. Это С++.

А не объясните ли, как Ваше сравнение вяжется с контекстом замечания ?! 

Цитата(Леопольд @  1.7.2009,  17:06 Найти цитируемый пост)
Но можно привязать способ очистки к способу выделения памяти, а не к типу объекта.Я полагаю, mes, имел ввиду именно это.

 smile


Автор: Леопольд 1.7.2009, 20:29
Цитата(mes @ 1.7.2009,  20:20)
Цитата(Леопольд @  1.7.2009,  17:06 Найти цитируемый пост)
Я убрал вчера контейнер и сделал из объектов стек. Каждый объект удаляет предыдущий.

Позвольте узнать зачем ? а также хотелось бы услышать какую задачу должен решать Ваш компонент ? (а то обсуждаем зверя о сути которого нам практически ничего неизвестно smile )

Это коллекция разнотипных указателей (отсюда виртуальный деструктор), память на которую они указывают, освобождается одновременно с разрушением объекта хранящего коллекцию. Это единственное предназначение. 

На мой взгляд, идея о жёсткой связи способа выделения и способа освобождения памяти очень хороша.

Добавлено @ 20:31
Цитата(mes @ 1.7.2009,  20:20)
Цитата(Леопольд @  1.7.2009,  17:06 Найти цитируемый пост)
Цитата(Леопольд @  1.7.2009,  17:06 Найти цитируемый пост)
никто не мешает мне передать в метод push что угодно smile 

И ничего удивительного. Даже константность можно снять приведением типов. Это С++.

А не объясните ли, как Ваше сравнение вяжется с контекстом замечания ?!

Именно с контекстом, никак. Но смысл есть... smile Всегда можно сделать не так как предназначено.

Автор: mes 2.7.2009, 00:35
Цитата(Леопольд @  1.7.2009,  19:29 Найти цитируемый пост)
Именно с контекстом, никак. Но смысл есть... smile Всегда можно сделать не так как предназначено.

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

разницу надеюсь почувствовали smile

Цитата(Леопольд @  1.7.2009,  19:29 Найти цитируемый пост)

Это коллекция разнотипных указателей (отсюда виртуальный деструктор), память на которую они указывают, освобождается одновременно с разрушением объекта хранящего коллекцию. Это единственное предназначение. 

прежде всего сформулируйте, пожалуйста, для чего в Вашем случае необходимо хранить объекты как коллекцию  ?

Автор: DrHex 2.7.2009, 00:45
Цитата

прежде всего сформулируйте, пожалуйста, для чего в Вашем случае необходимо хранить объекты как коллекцию  ?


Поддержую.....

Для сборки мусора, а точнее освобождению освобождения линамической памяти можно, используются smart-poiner, а фантаций в их реализации куча. Можно есче конечно написать аллокатор, и использовать как для выделения памяти так и для освобождения. Но выделять память, а потом добовлять указатели на эту память в контейнер что бы потом удалить, это нонсанс!!!
 



Автор: Lazin 2.7.2009, 05:53
Цитата(Леопольд @  1.7.2009,  18:06 Найти цитируемый пост)
Но можно привязать способ очистки к способу выделения памяти а не к типу объекта
вывод конечно гениальный, но по моему это и так очевидно, и все с этим согласны.. smile

Цитата(Леопольд @  1.7.2009,  18:06 Найти цитируемый пост)
И ничего удивительного. Даже константность можно снять приведением типов. Это С++

когда речь идет о интерфейсе класса, то желательно, что-бы он был сделан так, что-бы не допустить возможность неправильного использования smile 

Автор: Леопольд 2.7.2009, 20:08
Всем спасибо! Противопоставить нечего, потому что сам думаю так же...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)