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


Автор: fear 24.2.2010, 21:07
Нужен умный указатель, который бы освобождал память, занимаемую связанным с ним объектом, в том случае, если объект больше не используется (на объект не указывает ни один указатель). При этом умный указатель должен вести себя как и безумный стандартный, например, должна быть возможность динамически связать его как с объектом базового класса, так и с производным от базового. Boost пользовать в проекте только из-за одного класса не хочется.

В итоге, получился такой код. Но как то хочется его допилить и сделать более элегантным, есть идеи? smile

Код

#include <iostream>
using namespace std;

class ObjectA
{
  public:
    ObjectA() {}
    virtual int x() const { return 1; }
    virtual ObjectA *clone() const { return new ObjectA; }
};

class ObjectB: public ObjectA
{
  public:
    ObjectB() {}
    int y() const { return 2; }
    virtual ObjectB *clone() const { return new ObjectB; }
};

template <typename ObjectT>
class SmartPointer
{
  public:
    SmartPointer()
      :obj_(0), use_(new size_t(1)) {}

    explicit SmartPointer(ObjectT *obj)
      :obj_(obj), use_(new size_t(1)) {}

    SmartPointer(const ObjectT &obj)
      :obj_(obj.clone()), use_(new size_t(1)) {}

    SmartPointer(const SmartPointer &other) {
      copy(other);
      incrUse();
    }

    virtual ~SmartPointer() {
      decrUse();
    }

    SmartPointer &operator=(const SmartPointer &other) {
      other.incrUse();
      decrUse();
      copy(other);
      return *this;
    }

    const ObjectT *operator->() const {
      if(obj_)
        return obj_;
    }

    const ObjectT &operator*() const {
      if(obj_)
        return *obj_;
    }

  protected:
    ObjectT *obj() const {
      return obj_;
    }

  private:
    virtual void copy(const SmartPointer &other) {
      obj_ = other.obj_;
      use_ = other.use_;
    }

    void clean() {
      if(obj_)
      {
        delete obj_;
        obj_ = 0;
      }
      if(use_)
      {
        delete use_;
        use_ = 0;
      }
    }

    void incrUse() const {
      ++*use_;
    }

    void decrUse() {
      if(--*use_ == 0)
        clean();
    }

    ObjectT *obj_;
    mutable size_t *use_;
};

template <typename BaseT, typename DescendantT>
class SmartPointerDescendant: public SmartPointer<BaseT> {
  public:
    SmartPointerDescendant()
      :SmartPointer<BaseT>() {}
    SmartPointerDescendant(const DescendantT &obj)
      :SmartPointer<BaseT>(obj) {}
    explicit SmartPointerDescendant(DescendantT *obj)
      :SmartPointer<BaseT>(obj) {}
    SmartPointerDescendant(const SmartPointer<BaseT> &other)
      :SmartPointer<BaseT>(other) {}
    SmartPointerDescendant(const SmartPointerDescendant &other)
      :SmartPointer<BaseT>(other) {}

    const DescendantT *operator->() const {
      if(DescendantT *obj = static_cast<DescendantT *>(SmartPointer<BaseT>::obj()))
        return obj;
    }

    const DescendantT &operator*() const {
      if(DescendantT *obj = static_cast<DescendantT *>(SmartPointer<BaseT>::obj()))
        return *obj;
    }

  private:
    class Base: public SmartPointer<BaseT> {};

};

int main()
{
  //SmartPointerDescendant<ObjectA, ObjectB> b( (ObjectB()) );
  SmartPointerDescendant<ObjectA, ObjectB> b( new ObjectB );
  SmartPointer<ObjectA> a = b;

  cout<<b->x()<<endl;
  cout<<a->x()<<endl;
  cout<<static_cast< SmartPointerDescendant<ObjectA, ObjectB> >(a)->y()<<endl;
}


Автор: azesmcar 24.2.2010, 21:12
Лучше не выдумывай велосипеды а подключи boost, проблем с таким smartPointer-ом потом не оберешься. Аппетит приходит во время еды, подключишь boost и сразу появятся другие функции, которые понадобяться. Там много полезного. 

Просто пару замечаний, которые сразу попались на глаза, не вдавался в подробности
1. Зачем нужно наследование?
Код

    const ObjectT *operator->() const {
      if(obj_)
        return obj_;
    }

2. Где функция для НЕ константного указателя? Так выходит что можно вызывать только константные функции класса.
3. Что возвращяет функция в случае else? Ничего, что будет? Неясно.
4. mutable какой-то явно тут не нужный...

в общем хочешь хороший smart pointer - используй boost, ну или скопируй оттуда в крайнем случае.

Автор: fear 24.2.2010, 21:26
Цитата
1. Зачем нужно наследование?

чтобы могли сделать так:
SmartPointer<ObjectA> a = b;
если есть альтернативное решение, привести один класс умного указателя к другому (для случая, когда упровляемые объекты наследуются один от другого), оч интересно послушать

Цитата
2. Где функция для НЕ константного указателя? Так выходит что можно вызывать только константные функции класса.

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

Цитата
3. Что возвращяет функция в случае else? Ничего, что будет? Неясно.

Это интересный вопрос smile пока что я думаю, единственно верный ход - выбрасывать исключение

Цитата
4. mutable какой-то явно тут не нужный...

можно и без него

Автор: azesmcar 24.2.2010, 21:31
fear

Честно говоря сейчас лень смотреть, я по вечерам ленивый..если не будет ответов утром с работы подробно прокомментирую.

Автор: fear 24.2.2010, 23:02
Цитата(azesmcar @ 24.2.2010,  21:31)
fear
Честно говоря сейчас лень смотреть, я по вечерам ленивый..если не будет ответов утром с работы подробно прокомментирую.

участие в обсуждении темы по желанию, любое мнение ценно smile

Автор: andrew_121 24.2.2010, 23:15
Цитата(fear @  24.2.2010,  23:02 Найти цитируемый пост)
участие в обсуждении темы по желанию

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

Автор: fear 24.2.2010, 23:22
Цитата(andrew_121 @ 24.2.2010,  23:15)
установи нормальный компилятор, тогда буст тягать не придется. т.к. все уже встроено. и смарт поинтеры в том числе.

это что за компиляторы такие, в которых все встроено? smile

Автор: andrew_121 24.2.2010, 23:23
gcc-4.4.3 и выше. а gcc-4.4.5 уже и лямбда поддерживает. и extern template.

Добавлено через 1 минуту и 4 секунды
под вендавз это mingw32 зовется.

Добавлено через 2 минуты и 1 секунду
а вообще тут все описано: http://gcc.gnu.org/gcc-4.5/cxx0x_status.html

Автор: fear 24.2.2010, 23:42
Цитата
gcc-4.4.3 и выше. а gcc-4.4.5 уже и лямбда поддерживает. и extern template.

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

Цитата
под вендавз это mingw32 зовется.

спасибо конечно, но виндовс мне не нада, упоси smile

Автор: andrew_121 24.2.2010, 23:51
Цитата(fear @  24.2.2010,  23:42 Найти цитируемый пост)
да и сыровата версия 4.4.3

это релиз smile 

Цитата(fear @  24.2.2010,  23:42 Найти цитируемый пост)
не говоря уже о 4.4.5.

упс, опечатался. gcc-4.5.0. да, сыровата. но тесты все проходит. все что я этой версией компилил, работает без глюков.

Цитата(fear @  24.2.2010,  23:42 Найти цитируемый пост)
можно примерчик?

Код

#include <memory>

std::string my_mega_reader(std::shared_ptr<FILE> file) {
   ....
}

int main() {
   std::shared_ptr<FILE> file(fopen("", ""));
   return 0;
}


Добавлено через 2 минуты и 28 секунд
Цитата(fear @  24.2.2010,  23:42 Найти цитируемый пост)
спасибо конечно, но виндовс мне не нада, упоси

тогда не понятно в чем проблема? смарт поинтеры появились начиная с версии 4.4.0

Автор: fear 25.2.2010, 00:16
Цитата
это релиз smile 

ага, но свежий очень

Цитата
std::shared_ptr<FILE> file(fopen("", ""));

я что-то и не заметил, над посматреть

Цитата
тогда не понятно в чем проблема? смарт поинтеры появились начиная с версии 4.4.0

лень проблема smile я счас под macos тут в портах 4.2.1 самая свежая; завел убунту под вбоксом, ставлю 4.4.1 из репозитория smile

Автор: andrew_121 25.2.2010, 00:23
Цитата(fear @  25.2.2010,  00:16 Найти цитируемый пост)
я счас под macos тут в портах 4.2.1

да, у них с этим туго. я недели две назад пытался 4.4.2 установить. дня два бился. не сумел :(

Цитата(fear @  25.2.2010,  00:16 Найти цитируемый пост)
завел убунту под вбоксом, ставлю 4.4.1 из репозитория

да только эта и есть.

остальные версии нужно с сорцов ставить. но там сложностей не возникает.

Автор: fear 25.2.2010, 00:35
Цитата
остальные версии нужно с сорцов ставить. но там сложностей не возникает.

сложности появяться когда пересобирать все будешь под новую версию smile

Автор: andrew_121 25.2.2010, 00:55
Цитата(fear @  25.2.2010,  00:35 Найти цитируемый пост)
сложности появяться когда пересобирать все будешь под новую версию

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

char* str = "str"; // const to non const

Автор: bsa 25.2.2010, 17:03
fear, имей в виду, что andrew_121 говорит про фичи, которые будут в БУДУЩЕМ стандарте С++, но которые поддерживаются GCC в экспериментальном режиме (нужно указывать специальный ключ).
Пока стандарт не принят, лучше использовать старый добрый boost.

Автор: andrew_121 25.2.2010, 17:46
Цитата(bsa @  25.2.2010,  17:03 Найти цитируемый пост)
Пока стандарт не принят, лучше использовать старый добрый boost. 

как бы да. но, обратно все равно не вернется. раз уж начали реализовывать новый стандарт все производители компиляторов, то нужно не опоздать на него smile 
особенно если учесть, что все самое нужное(thread, mutex, smart pointers, function, lambda, bind, и т.д.), уже есть поддерживающих его компиляторах.

Добавлено через 2 минуты и 52 секунды
Цитата(bsa @  25.2.2010,  17:03 Найти цитируемый пост)
которые поддерживаются GCC в экспериментальном режиме

а как же микрософтстудия2010? там ведь это отключить невозможно?

Автор: fear 25.2.2010, 18:06
Цитата

fear, имей в виду, что andrew_121 говорит про фичи, которые будут в БУДУЩЕМ стандарте С++, но которые поддерживаются GCC в экспериментальном режиме (нужно указывать специальный ключ).

да, я это понимаю, по этой причине и пример выше над подредактировать, собирать надо с ключем -std=c++0x
Код

#include <memory>
#include <bits/shared_ptr.h>

int main(int argc, char **argv)
{
  std::shared_ptr<int> ptr;
}


Цитата

Пока стандарт не принят, лучше использовать старый добрый boost.

не хотелось бы, как, впрочем, и не хочется городить костыли; кстати shared_ptr в стандартную библиотеку собирается прийти как раз оттуда

andrew_121, на счет проблем не так все просто, поставить gcc 4.5 можно оказывается даж из портов, но вот собрать ту же qt с его помощью под mac не такая как оказалась простая задача

Автор: andrew_121 25.2.2010, 18:23
Цитата(fear @  25.2.2010,  18:06 Найти цитируемый пост)
andrew_121, на счет проблем не так все просто, поставить gcc 4.5 можно оказывается даж из портов, но вот собрать ту же qt с его помощью под mac не такая как оказалась простая задача

у меня без проблем собралась. и буст тоже(но чуток пришлось подправить).

посмотри дату того из портов. т.к. 4.5.0 выходит раз в неделю(иногда два).
последняя сборка - 2010.02.18

Добавлено @ 18:25
вообще то, 4.4.3 зарелизен месяц назад.

Добавлено @ 18:26
Цитата(fear @  25.2.2010,  18:06 Найти цитируемый пост)
#include <bits/shared_ptr.h>

мне не нужно подключать этот хидер.
мало того, из bits/ ничего нельзя подключать напрямую. препроцессор орет, и завершается.

Добавлено @ 18:27
Цитата(fear @  25.2.2010,  18:06 Найти цитируемый пост)
кстати shared_ptr в стандартную библиотеку собирается прийти как раз оттуда

так все оттуда smile 

Автор: fear 25.2.2010, 18:43
Цитата

последняя сборка - 2010.02.18


не обновили пока значит smile

Цитата

Target: x86_64-apple-darwin10
Configured with: ../gcc-4.5-20100211/configure --prefix=/opt/local --build=x86_64-apple-darwin10 --enable-languages=c,c++,objc,obj-c++ --libdir=/opt/local/lib/gcc45 --includedir=/opt/local/include/gcc45 --infodir=/opt/local/share/info --mandir=/opt/local/share/man --with-local-prefix=/opt/local --with-system-zlib --disable-nls --program-suffix=-mp-4.5 --with-gxx-include-dir=/opt/local/include/gcc45/c++/ --with-gmp=/opt/local --with-mpfr=/opt/local --with-mpc==/opt/local --enable-stage1-checking
Thread model: posix
gcc version 4.5.0 20100211 (experimental) (GCC)


Цитата

у меня без проблем собралась. и буст тоже(но чуток пришлось подправить).

это под линухом так smile а тут не так все просто:

cc1plus: error: unrecognized command line option "-arch"

Автор: fear 1.3.2010, 19:03
буду пользовать boost smile

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