Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Велосипед: Полуумный указатель

87
26 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Решил воспользоваться умными указателями. Думал вытащить shared_ptr из boost, но увидел, что придется половину boost выколупывать. А boost мне пока не нужен. В принципе, можно было бы какой-нибудь компилятор раздобыть, который уже поддерживает будущий стандарт C++, но тут велика вероятность, что с другим компилятором мой код может быть не совсем совместим. Да и возиться лень.

Так как мне нужно выполнение только основной логики, решил сделать велосипед, реализующий только основное назначение shared_ptr (вызывать delete, когда объект никому не нужен). Если кому не лень, посмотрите сильно ли кривой вышел велосипед.

Код:
template<class T>
class Half_Ptr
{
    struct HalfObject // прилепляет к объекту счетчик указателей
    {
        unsigned int counter;
        T *targetObject;
        HalfObject(T *tOb):counter(0), targetObject(tOb){}
        virtual ~HalfObject()
        {
            // cout << "ksObject deleted" << endl; - проверка
            delete targetObject;
        }
    };

    HalfObject *objPtr;

    void DecPtr()
    {
        if (objPtr)
        {
            objPtr->counter--;
            if (!objPtr->counter)
                delete objPtr;
        }
    }

public:

    Half_Ptr():objPtr(0)
    {

    }

    ~Half_Ptr()
    {
        DecPtr();
    }

    Half_Ptr(T* ref)
    {
        objPtr = new HalfObject(ref);
        if (objPtr)
            objPtr->counter++;
    }

    Half_Ptr(const Half_Ptr<T>& ref)
    {
        objPtr = ref.objPtr;
        if (objPtr)
            objPtr->counter++;
    }


    Half_Ptr operator=(const Half_Ptr<T>& ref)
    {
        DecPtr();

        objPtr = ref.objPtr;
        if (objPtr)
            objPtr->counter++;
        return *this;
    }

    T* operator->()
    {
        return this->objPtr->targetObject;
    }

// для проверки
    unsigned GetCounter()
    {
        if (objPtr) return objPtr->counter;
        return 0;
    }
};


// Проверка работы

struct TestObject
{
    int m;
    TestObject(int m):m(m)
    {
    }
    ~TestObject()
    {
        cout << "TestObject deleted: " << m << endl;
    }
};

int main()
{
    typedef Half_Ptr<TestObject> refType;

    refType myPtr3;
    {
        refType myPtr(new TestObject(20));
        cout << myPtr->m << endl;
        cout << "Counter: " << myPtr.GetCounter() << endl;

        refType myPtr2 = myPtr;
        cout << myPtr2->m << endl;
        cout << "Counter: " << myPtr2.GetCounter() << endl;

        myPtr3 = myPtr2;

    }
    cout << myPtr3->m << endl;
    cout << "Counter: " << myPtr3.GetCounter() << endl;

    {
        vector<refType > myVector;

        myVector.push_back(new TestObject(1));
        myVector.push_back(new TestObject(2));
        myVector.push_back(new TestObject(3));
        myVector.push_back(new TestObject(4));
        myVector.push_back(new TestObject(5));

        myPtr3 = myVector[0];

        for (size_t i = 0; i < myVector.size(); ++i)
        {
            cout << myVector->m << endl;
        }
    }
    {
        vector<refType > myVector(5, refType(new TestObject(77)));
        myVector[0]->m++;

        for (size_t i = 0; i < myVector.size(); ++i)
        {
            cout << myVector->m << endl; // 78 для всех - объект один
        }
    }
    cout << myPtr3->m << endl;

    return 0;
}
294
26 июня 2009 года
Plisteron
982 / / 29.08.2003
Цитата: Kogrom
Если кому не лень, посмотрите сильно ли кривой вышел велосипед.


[quote=ВсемИзвестныйФильм]Не скрою, это от души. Ложки у меня пациенты много раз глотали, но чтобы вот так -- за обедом и острый предмет... За это Вам наше искреннее мерси. Ежели, конечно, кроме железных предметов, ещё и фарфор можете употребить, тогда... Слов нет.[/quote]
Я хотел сказать: а что-то аналогичное для массивов? Т.е. чтобы память выделялась при создании контейнера на указанное количество элементов и освобождалась, когда разрушается последний экземпляр контейнера.

PS. Отладка методом пристального всматривания косяков не обнаружила.

87
26 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Plisteron
Я хотел сказать: а что-то аналогичное для массивов? Т.е. чтобы память выделялась при создании контейнера на указанное количество элементов и освобождалась, когда разрушается последний экземпляр контейнера.


Есть boost::shared_array, boost::scoped_array, но мне они пока не нужны. Когда нужных фич из boost станет много - то просто добавлю boost.

Цитата: Plisteron
PS. Отладка методом пристального всматривания косяков не обнаружила.



Моя подобная отладка обнаружила пару сомнительных мест.

Тут вроде бы проверка лишняя. Правильнее исключение ловить.

 
Код:
objPtr = new HalfObject(ref);
        if (objPtr)


Ну и как-то странно, что компилятор переварил, что класс является сам себе другом (friend) по умолчанию. То есть один объект свободно обращается к закрытым полям объекта этого же класса. Хотя, может так и должно быть.
294
26 июня 2009 года
Plisteron
982 / / 29.08.2003
Цитата: Kogrom
Есть boost::shared_array, boost::scoped_array, но мне они пока не нужны. Когда нужных фич из boost станет много - то просто добавлю boost.

Так ведь сам предложил по возможности без boost обойтись.

Цитата: Kogrom
Тут вроде бы проверка лишняя. Правильнее исключение ловить.
 
Код:
objPtr = new HalfObject(ref);
        if (objPtr)

Это в конструкторе? Имхо, пусть программист, использующий твою библиотеку, сам думает, что он конструктору передаёт.

Цитата: Kogrom
Ну и как-то странно, что компилятор переварил, что класс является сам себе другом (friend) по умолчанию. То есть один объект свободно обращается к закрытым полям объекта этого же класса. Хотя, может так и должно быть.

Саму себе в друзья набиваться, конечно, бессмысленно, но не противоречит синтаксису и семантике оператора friend. А я, кстати, этого в коде и не заметил... Да, спать... спать...

276
26 июня 2009 года
Rebbit
1.1K / / 01.08.2005
Так к слову. Фильм етот всем известный - Формула любви кажется.
87
26 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Plisteron
Так ведь сам предложил по возможности без boost обойтись.


Стратегия такая: у меня есть "походная" IDE, которую я могу быстро поставить на разные компьютеры, чтобы отлаживать свои приложения. Поэтому стараюсь по возможности не использовать библиотек, которые не поставляются вместе с компилятором. Может, зря.

Возможно, стоит собрать свой дистрибутив IDE на основе Code::Blocks, чтобы не мучиться.

Цитата: Plisteron
Имхо, пусть программист, использующий твою библиотеку, сам думает, что он конструктору передаёт.



Хм. Мою библиотеку... Тут нужен то всего один хедер. Хотя, я и до этого простые куски из Boost вытаскивал. Скоро издам микроБуст :)

Или не выдержу и пойду осваивать какой-нибудь D...

294
27 июня 2009 года
Plisteron
982 / / 29.08.2003
Цитата: Rebbit
Так к слову. Фильм етот всем известный - Формула любви кажется.

Он самый. :)

Цитата: Kogrom
Или не выдержу и пойду осваивать какой-нибудь D...

Лучше J. :D

87
27 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: Plisteron
Лучше J.



Что толку от этого J ? - только поиграться. Да и вообще - проприетарщина какая-то. Для поиграться у меня Python есть. Про D я агитации прочитал - вроде красиво. Примерно то же, что и C++, но там такой велосипед не нужен. А что на деле - не знаю, надо будет как-нибудь проверить.

5
28 июня 2009 года
hardcase
4.5K / / 09.08.2005
Цитата: Kogrom
Про D я агитации прочитал - вроде красиво.

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

294
28 июня 2009 года
Plisteron
982 / / 29.08.2003
Цитата: Kogrom
Что толку от этого J ? - только поиграться.

Имхо, для обработки всяких массивов информации J -- самое то. Хотя, есть ещё MatLab.

41K
29 июня 2009 года
phantomka
8 / / 22.09.2008
Kogrom, если хотите изобрести велосипед, то есть книга Джеффа Элджера "Библиотека программиста С++". На мой взгляд, книга интересная :) Может, найдете что-нибудь полезное
87
29 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: phantomka
Kogrom, если хотите изобрести велосипед, то есть книга Джеффа Элджера "Библиотека программиста С++". На мой взгляд, книга интересная :) Может, найдете что-нибудь полезное



Читал. Правда через строчку и не все главы... Некоторые главы устарелые. Некоторые я просто не смог переварить - не дорос наверное.

87
29 июня 2009 года
Kogrom
2.7K / / 02.02.2008
Сделал более гибкую, но более "пахабную" версию - с использованием void* (не придумал пока как от него избавиться)... Теперь можно присваивать и переприсваивать "абстрактному" родительскому указателю конкретные дочерние.
Код:
struct HalfBase
{
    virtual void Inc() = 0;
    virtual int Dec() = 0;
    virtual void* Get() = 0;
    virtual int GetCounter() = 0;
    virtual ~HalfBase(){cout << "HalfBase deleted" << endl;}
};

template<class T>
class Half_Ptr
{

    struct HalfObject: public HalfBase // This one must add counter of pointers to object
    {
        unsigned int counter;
        T *targetObject;
        HalfObject(T *tOb):counter(0), targetObject(tOb){}
        void Inc()
        {
            ++counter;
        }
        int Dec()
        {
            return --counter;
        }
        void* Get()
        {
            return targetObject;
        }
        int GetCounter()
        {
            return counter;
        }
        ~HalfObject()
        {
            cout << "HalfObject deleted" << endl; //- old test
            delete targetObject;
        }
    };


public:

    HalfBase *objPtr;

    void DecPtr()
    {
        if (objPtr)
        {
            if (!objPtr->Dec())
                delete objPtr;
        }
    }

    Half_Ptr():objPtr(0)
    {
    }

    ~Half_Ptr()
    {
        DecPtr();
    }

    Half_Ptr(T* ref)
    {
        objPtr = new HalfObject(ref);
        objPtr->Inc();
    }

    Half_Ptr(const Half_Ptr<T>& ref)
    {
        objPtr = ref.objPtr;
        if (objPtr)
            objPtr->Inc();
    }

    template<class F>
    Half_Ptr operator=(const Half_Ptr<F>& ref)
    {
        DecPtr();

        objPtr = ref.objPtr;
        if (objPtr)
            objPtr->Inc();
        return *this;
    }

    Half_Ptr operator=(const Half_Ptr<T>& ref)
    {
        DecPtr();

        objPtr = ref.objPtr;
        if (objPtr)
            objPtr->Inc();
        return *this;
    }

    T* operator->()
    {
        return static_cast<T*>( this->objPtr->Get());
    }

    // for test
    unsigned GetCounter()
    {
        if (objPtr) return objPtr->GetCounter();
        return 0;
    }
};


// Проверка работы
struct TestBase
{
    virtual void print() = 0;
    virtual ~TestBase(){cout << "TestBase deleted" << endl;}
};


struct TestObject1: public TestBase
{
    int m;
    void print()
    {
        cout << "TestObject1.m: " << m << endl;
    }
    TestObject1(int m):m(m)
    {
    }
    ~TestObject1()
    {
        cout << "TestObject1 deleted: " << m << endl;
    }
};

struct TestObject2: public TestBase
{
    int m;
    void print()
    {
        cout << "TestObject2.m^2: " << m*m << endl;
    }
    TestObject2(int m):m(m)
    {
    }
    ~TestObject2()
    {
        cout << "TestObject2 deleted: " << m << endl;
    }
};

int main()
{
    Half_Ptr<TestBase> myBasePtr;

    {
        Half_Ptr<TestObject1> myPtr(new TestObject1(20));
        myBasePtr = myPtr;
        myPtr->print();
    }


    myBasePtr->print();

    cout << endl;
    {
        Half_Ptr<TestObject2> myPtr(new TestObject2(30));
        myBasePtr = myPtr;
        myPtr->print();
    }

    myBasePtr->print();

    return 0;
}
240
29 июня 2009 года
aks
2.5K / / 14.07.2006
Цитата: Plisteron
Имхо, для обработки всяких массивов информации J -- самое то.


Факт. Да и не только массивов.

350
01 июля 2009 года
cheburator
589 / / 01.06.2006
Цитата: Kogrom
...но увидел, что придется половину boost выколупывать


Что значит "выколупывать"?
Достаточно одной строки:

 
Код:
include <boost/shared_ptr.hpp> // зависит от того, где у вас буст находится - я его влепил в директорию с инклюдами
using namespace boost; // необязательно

...

shared_ptr<MyClass> ptr; // или boost::shared_ptr<MyClass> ptr, если не хотите использовать using namespace

Помнится, как-то так... К сожалению, нет студии под рукой.
Может, ваша ошибка в том и состоит, что вы не поняли, как с бустом работать?
87
01 июля 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: cheburator
Что значит "выколупывать"?
Достаточно одной строки:
 
Код:
include <boost/shared_ptr.hpp> // зависит от того, где у вас буст находится - я его влепил в директорию с инклюдами
using namespace boost; // необязательно
...
shared_ptr<MyClass> ptr; // или boost::shared_ptr<MyClass> ptr, если не хотите использовать using namespace


Это все понятно.

Мне нужна маленькая "походная" IDE, которую я могу использовать на случайном компьютере. Ну, пусть в нем стоит Windows 2000/XP/Wista. Сейчас я могу за полминуты установить IDE и работать.

Складывать в нее более 300 мегабайт непонятного кода неохота. Зачем мне оно надо, если требуются только умные указатели?

Есть конечно утилита boost bcp, но это решение не очень элегантное. Я посмотрел состав компилятора gcc 4.4.0 - туда уже включили эти указатели, чтобы соответствовать грядущему стандарту. Буду копать в сторону использования этого компилятора.

350
01 июля 2009 года
cheburator
589 / / 01.06.2006
Цитата: Kogrom
Сейчас я могу за полминуты установить IDE и работать.
Складывать в нее более 300 мегабайт непонятного кода неохота. Зачем мне оно надо, если требуются только умные указатели?


Лично мой буст 1.33.0 (может, я и отстал от жизни, но вряд ли он в разы вырос), я измерил вес, получил менее 100М. А подпапка boost (без doc, lib и т. д. - они не нужны) около 20М.
Не проще ли заархивировать её и носить на флэшке, распаковывая напрямик в папку инклюдов вашего IDE :)
А если вам и 20 метров не нравится, то из boost выбросьте все подпапки (не файлы), кроме detail и config, у меня после такого хирургического вмешательства осталось 1,3 м и все виды умных указателей прекрасно компилируются. Если что непонятно, вложил скриншот :)

350
01 июля 2009 года
cheburator
589 / / 01.06.2006
Ну, или совсем экстремальный вариант (см. скриншот).
Да всё это выясняется экспериментальным путём, могли бы и сами выяснить :)
Весит 608 Кб
288
01 июля 2009 года
nikitozz
1.2K / / 09.03.2007
Цитата: cheburator
Лично мой буст 1.33.0 (может, я и отстал от жизни, но вряд ли он в разы вырос), я измерил вес, получил менее 100М. А подпапка boost (без doc, lib и т. д. - они не нужны) около 20М.
Не проще ли заархивировать её и носить на флэшке, распаковывая напрямик в папку инклюдов вашего IDE :)
А если вам и 20 метров не нравится, то из boost выбросьте все подпапки (не файлы), кроме detail и config, у меня после такого хирургического вмешательства осталось 1,3 м и все виды умных указателей прекрасно компилируются. Если что непонятно, вложил скриншот :)



Согласен с Kogrom. Если boost в разработке обычно не используется, не вижу смысла использовать ее только из-за одного класса.

350
01 июля 2009 года
cheburator
589 / / 01.06.2006
Цитата: nikitozz
Согласен с Kogrom. Если boost в разработке обычно не используется, не вижу смысла использовать ее только из-за одного класса.


А вот я несогласен, потому что
1) К велосипедостроению всегда отношусь плохо, разве что с целью самообразования и тренировки
2) буст кроссплатформенный, и будет под любым IDE работать, тем более, что автор упомянул "случайный компьютер"
3) буст проверен многими годами, а самописный код глюкнет на "случайном компьютере" и сиди разбирайся
4) буст собсно создан как совокупность многих библиотечек, а не как одна жирная Библия (верующие да не сочтят за оскорбление) именно для того, чтобы каждую отдельную возможность ("библиотеку") можно было использовать независимо от остальных, а конкретные разжёванные рекомендации по волшебному похудению даны чуть выше

87
01 июля 2009 года
Kogrom
2.7K / / 02.02.2008
Цитата: cheburator
Ну, или совсем экстремальный вариант (см. скриншот).
Да всё это выясняется экспериментальным путём, могли бы и сами выяснить :)
Весит 608 Кб



Ну, может надо посмотреть в старой библиотеке. В той, что у меня в хедере shared_ptr.hpp кроме сторожа включения и комментариев только одна строчка:

#include <boost/smart_ptr/shared_ptr.hpp>

то есть придется еще папки включать. Но вообще, идея понятна.

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

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог