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

интеллектуальные указатели - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 17, средняя оценка - 4.71
AnreyKazakov
Заблокирован
07.10.2012, 00:39     интеллектуальные указатели #1
Блин, не совсем понял зачем такой геморой нужен как эти указатели, но фиг с ним вопрос основной по коду, вот сделал по примеру с учебника, может есть косяки, вопросы выделил комментариями...
примкр класса1 и пример класса2, через кот передаются указатели классу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
#include <iostream>
using namespace std;
 
class use_point{
    friend class point;
    int* usei;
    size_t ix;
    use_point(int *iop):usei(iop),ix(1){}
    ~use_point(){delete usei;}
    };
 
class point{
    public:
    point(int inpv,int* inprv):val(inpv),rival(new use_point(inprv)){}
    point(const point &copy):val(copy.val),rival(copy.rival){++rival->ix;}
    point &operator=(const point &copy){ /*здесь может я накосячил в объявлении*/
        ++copy.rival->ix;
        if(--copy.rival->ix==0)/*совсем не понятно предназначение этой строчки*/
        delete rival;
        val=copy.val;
        rival=copy.rival;
        return *this;
        }
    ~point(){if(--rival->ix==0) delete rival;}
        
    int get_val()const{return val;}
    int* get_ref()const{return rival->usei;}
    void set_val(int pval){val=pval;}
    void set_ref(int* pri){rival->usei=pri;}
    int get_ref_val()const{return *rival->usei;}
    void set_ref_val(int prival){*rival->usei=prival;}
    
    private:
    int val;
    use_point* rival;
    };
    
    int main(){
        int* ri=new int(777);
        point one(*ri,ri);
        delete ri;
        point two=one;
        cout<<two.get_ref()<<" "<<two.get_ref_val()<<endl;
        return 0;
        }

Вот к вопросу о нужности\ненужности таких указателей. В учебнике ставился пример что допустим у класса описанного сверху rival это обычный указатель тогда если в main прописать этот же код
C++
1
2
3
4
5
6
7
8
int main(){
        int* ri=new int(777);
        point one(*ri,ri);
        delete ri;
        point two=one;
        cout<<two.get_ref()<<" "<<two.get_ref_val()<<endl;
        return 0;
        }
то в присвоении point two=one; произойдет "КАТАСТРОФА".... Вот, поэтому давайте сделаем указатель интеллектуальный, и вся эта куча лишнего кода из-за того, что присваивание идет после удаления объекта на кот указывает указатель, но что мешает так прописать (по нормальному)
C++
1
2
3
4
5
6
7
int* ri=new int(777);
        point one(*ri,ri);
        point two=one;
        cout<<two.get_ref()<<" "<<two.get_ref_val()<<endl;
                      delete ri;
        return 0;
        }
Добавлено через 48 минут
editing
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.10.2012, 00:39     интеллектуальные указатели
Посмотрите здесь:

C++ Указатели
Указатели C++
Указатели. C++
Указатели C++
Указатели в С C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
07.10.2012, 00:42     интеллектуальные указатели #2
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Задача всех этих умных указателей: облегчить менеджмент памяти в случаях, когда владение указателями не сосредоточено где-то в одном месте, а может передаваться, разделятся и тому подобное. Естественно, всё это ценой определённой потери в скорости. Она не особо критична, но всё же есть.

Суть: reference counting. За каждым объектом закрепляется счётчик, который показывает, сколько указателей на этот объект в данный момент живы в программах. Вот это объединение объекта и счётчика называется smart pointer. Smart, потому что он может сам удалить охраняемый объект, когда никто больше не ссылается на него. Или, например, реализовывать операцию удаления объекта не только автоматически, но и принудительно, но все остальные клоны-указатели не будут указывать чёрти куда, а вежливо бросят в лицо исключение вместо того, чтобы тихо гадить память. (Естессно, это всё работает ещё и с предположением, что вы не будете использовать обычные указатели на объекты со счётчиками. По крайней мере в потенциально разрушительных целях.)

Если аккуратно следить за передачей владения объектами, вполне можно обойтись и без них. Но не у всех достаточно мозгов/терпения/времени, чтобы следить вручную/тщательно прорабатывать архитектуру и т. п.
AnreyKazakov
Заблокирован
07.10.2012, 10:02  [ТС]     интеллектуальные указатели #3
Все равно не очень понятно. Вот смотрим
задача - нужно чтобы в создаваемый объект класса х некое значение передовалось по ссылке, пусть i. Где-то этот i был создан в динамической памяти ( int* i =new int(10); ). Пусть он создан в main. Используем обычные указатели. Теперь каждый созданный объект класса х работает напрямую с этим указателем, захотел поменял значение, захотел не поменял, ну и соответственное значение меняется во всех остальных объектах класса х.... Вопрос как можно навредить такому коду? как можно с объекта класса удалить этот i, и зачем...
второе , все то же самое, но указатель интеллектуальный. В моем случае (кот описан в учебнике, код выше) при создании нового объекта класса х зачем то создается вспомогательный класс, пусть будет y. В нем содержится все та же ссылка на указатель i, он ничего не делает только хранит адрес i (передает его в новые обхекты класса х) и смотрит сколько раз его вызвали, считает, если счетчик = 0 , до срабатывает деструктор... Вопрос еще раз, зачем он нужен, этот класс y?
По сути дела если вдруг случайным образом удалить объект i ( delete i; ) то в обоих случаях произойдет ошибка, тогда в классе y, как я понимаю, нужно создавать копию i (int* j = new int(*i); ) . Все хорошо теперь работаем всеми классами с указателем j, никаких ошибок, i можно спокойно удалять. Тогда можно в main и не занимать динамич память, сразу в класс y запихивать значение *i, те (int* j=new int(10); ) и все.
PS Правильны ли суждения мои?
BRcr
 Аватар для BRcr
4003 / 2292 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
07.10.2012, 10:31     интеллектуальные указатели #4
Ты упускаешь одну очень важную вещь - при использовании умных указателей отпадает необходимость явно освобождать память динамически созданных объектов. Пока они нужны - они существуют, как только все копии указателя обнулились, память освобождается. Просто и ни о чем заботиться не надо.
Серьезный недостаток лишь один, это быстродействие. В алгоритмах, чувствительных к скорости умные указатели применять обычно нецелесообразно, так как они выполняют относительно избыточную работу.
soon
 Аватар для soon
2536 / 1301 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
07.10.2012, 10:36     интеллектуальные указатели #5
AnreyKazakov, исходя из того, что я понял, после прочтения вашего сообщения - программист сам себе злобный буратино. Используя умные указатели, вы освобождаете себя от необходимости держать в своей голове все указатели и в нужный момент освобождать память. Как следствие, можно сосредоточится на более важных задачах.

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
#include <iostream>
#include <memory>
 
struct Foo
{
    Foo()
    {
        std::cout << ' ' << this << std::endl;
    }
 
    ~Foo()
    {
        std::cout << '~' << this << std::endl;
    }
};
 
void func()
{
    Foo* ptr1(new Foo());
    std::shared_ptr<Foo> ptr2(new Foo());
 
    // Магиеские действия, приводящие к исключению
 
    throw 42;
 
    delete ptr1;
}
 
int main()
{
    try
    {
        func();
    }
    catch(...)
    {
 
    }
    return 0;
}
AnreyKazakov
Заблокирован
07.10.2012, 10:36  [ТС]     интеллектуальные указатели #6
Цитата Сообщение от BRcr Посмотреть сообщение
при использовании умных указателей отпадает необходимость явно освобождать память динамически созданных объектов
Покажите, пожалуйста, какой-нибудь простенький пример, бошка уже трещит будто с похмелья =(
BRcr
 Аватар для BRcr
4003 / 2292 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
07.10.2012, 10:53     интеллектуальные указатели #7
Куда уж проще - создаешь указатель, суешь ему адрес динамически созданного и забываешь.
Это чрезвычайно удобно с теми типами данных, что нельзя создавать статически, например, классы библиотеки VCL.
C++
1
std::auto_prt<TStringList> ptr( new TStringList( ) );
Можно делать их членами классов, тогда время жизни объекта будет либо совпадать с временем жизни экземпляра класса, либо, если указатель был скопирован, до момента разрушения его копии. Пока жив хоть один указатель, жив и объект.
AnreyKazakov
Заблокирован
07.10.2012, 11:24  [ТС]     интеллектуальные указатели #8
Цитата Сообщение от BRcr Посмотреть сообщение
Пока жив хоть один указатель, жив и объект.
Вот я наверно это пропускал...
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
struct danger{
    danger(int* intermedval):d(intermedval){};
    int get_d(){return *d;}
    private:
    int* d;
    };
 
int main(){
    int* i =new int (1050);
    danger dang(i);
    delete i;
    std::cout<<dang.get_d()<<std::endl;
    return 0;
    }
В этом примере память потеряется или нет?
soon
 Аватар для soon
2536 / 1301 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
07.10.2012, 11:28     интеллектуальные указатели #9
Цитата Сообщение от AnreyKazakov Посмотреть сообщение
В этом примере память потеряется
Разумеется
AnreyKazakov
Заблокирован
07.10.2012, 12:40  [ТС]     интеллектуальные указатели #10
Все, врубился, всем спасибо

Добавлено через 1 час 9 минут
Т.е. если применять в классе обычные указатели, тк в конце обязательно нужно delete в деструктор пихать, то в процессе освобождения объектами этого класса памяти указатель будет удалятся.... что же будет показывать указатель, кот показывает на объект, который был удален?
И еще кусок кода с учебника, кот опис класс, не могу понять его (сверху в 1 сообщ весь код)
C++
1
2
3
4
5
6
7
8
point &operator=(const point &copy){ /*здесь может я накосячил в объявлении*/
        ++copy.rival->ix;
        if(--copy.rival->ix==0)/*совсем не понятно предназначение этой строчки*/
        delete rival;
        val=copy.val;
        rival=copy.rival;
        return *this;
        }
BRcr
 Аватар для BRcr
4003 / 2292 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
07.10.2012, 12:56     интеллектуальные указатели #11
Цитата Сообщение от AnreyKazakov Посмотреть сообщение
что же будет показывать указатель, кот показывает на объект, который был удален?
Мусор в лучшем случае, access violation в худшем.
Jupiter
Каратель
Эксперт C++
6543 / 3963 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
07.10.2012, 13:00     интеллектуальные указатели #12
Цитата Сообщение от BRcr Посмотреть сообщение
Мусор в лучшем случае, access violation в худшем.
как раз таки наоборот, access violation в лучшем случае ибо ошибка будет выявлена
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
07.10.2012, 13:32     интеллектуальные указатели #13
Цитата Сообщение от AnreyKazakov Посмотреть сообщение
Т.е. если применять в классе обычные указатели, тк в конце обязательно нужно delete в деструктор пихать, то в процессе освобождения объектами этого класса памяти указатель будет удалятся.... что же будет показывать указатель, кот показывает на объект, который был удален?
Будет показывать "чёрти куда". Вот именно от этого немного защищают умные указатели: они не будут гадить память, они не заставят ОС прибить процесс из-за сегфолта. Они хотя бы выкинут исключение, которое можно обработать самостоятельно и попытаться восстановить работу (ну или хотя бы сохранить что можно куда-нибудь), а не просто пустить сегфолт на самотёк и заставить пользователя наложить в штаны от выпрыгивающего окошка про «ПАМЯТЬ НЕ МОЖЕТ БЫТЬ READ, приложение будет ЗАКРЫТО, а документ, над которым вы работали ТРИ ЧАСА и НЕ СОХРАНЯЛИСЬ, будет УДАЛЁН, мвахаха, обратитесь с жалобой и вот этим дампом памяти к разработчику».

Цитата Сообщение от AnreyKazakov Посмотреть сообщение
И еще кусок кода с учебника, кот опис класс, не могу понять его (сверху в 1 сообщ весь код)
Я вообще не понимаю, зачем там хранится и указатель, и значение. Вы точно уверены, что это smart pointer, а не что-то другое? То, что ix — это тот самый счётчик, очевидно. Вопрос, какого чёрта его дёргают туда-сюда, да ещё и в классе point. Это тайна для меня.
AnreyKazakov
Заблокирован
07.10.2012, 14:25  [ТС]     интеллектуальные указатели #14
Да, уверен, просто я пример не скопировал, а примерно сделал то же самое, класс point это я просто так его обозвал, без смысла так сказать, всегда хотел видеть продуктовый магазин с надписью "Инструменты" Но вот одну функцию я скопировал на 100%, хотя нет, оригинал оказывается чуть отличается
C++
1
2
3
4
5
6
7
8
9
10
11
//HasPtr - основной класс
//U_Ptr - вспомогательный, где счетчик сидит (use) и указатель (*ip)
//ptr - указатель на объект класса HasPtr
HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
    ++rhs.ptr->use;//сначала инкримент счетчика пользователей rhs
    if(--ptr->use==0)//если счетчик пользователей имеет значение 0 удалить этот объект
    delete ptr;
    ptr=rhs.ptr;//скопировать объект U_Ptr
    return *this
    }
Добавлено через 4 минуты
Цитата Сообщение от AnreyKazakov Посмотреть сообщение
удалить этот объект
зачем его удалять?
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
07.10.2012, 14:29     интеллектуальные указатели #15
Оно как минимум неочевидно. Можете бросить яблоком в того, откуда копировали.

Идея в том, что указатель из rhs замещает указатель из this. Следовательно, количество ссылок на объект, на который ссылается rhs, увеличивается на единицу, а тот объект, на который до operator= ссылался this, теряет одну ссылку. Соответственно, если на него больше никто не ссылается, то его можно удалить.
BRcr
 Аватар для BRcr
4003 / 2292 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
07.10.2012, 14:31     интеллектуальные указатели #16
... и даже нужно...
soon
 Аватар для soon
2536 / 1301 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
07.10.2012, 14:33     интеллектуальные указатели #17
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
они не заставят ОС прибить процесс из-за сегфолта. Они хотя бы выкинут исключение
Не лазил в стандарт, там действительно прописано про исключения? Если да, то как можно вернуть(к примеру) невалидный shared_ptr? Пробовал через reset() - segfault.
AnreyKazakov
Заблокирован
07.10.2012, 14:41  [ТС]     интеллектуальные указатели #18
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
Идея в том, что указатель из rhs замещает указатель из this.
Еле понял. Чем дальше читаю cpp, тем больше чувствую себя жирафом...
BRcr
07.10.2012, 14:50
  #19

Не по теме:

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

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.10.2012, 15:13     интеллектуальные указатели
Еще ссылки по теме:

Указатели C++
Указатели C++
C++ Указатели

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

Или воспользуйтесь поиском по форуму:
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
07.10.2012, 15:13     интеллектуальные указатели #20
Цитата Сообщение от AnreyKazakov Посмотреть сообщение
Еле понял. Чем дальше читаю cpp, тем больше чувствую себя жирафом...
Вот потому и говорю про яблоки, что это не очевидно. А должно быть очевидно.

Цитата Сообщение от soon Посмотреть сообщение
Не лазил в стандарт, там действительно прописано про исключения? Если да, то как можно вернуть(к примеру) невалидный shared_ptr? Пробовал через reset() - segfault.
Это мокрые фантазии на тему, как оно может быть. Есть принципиальная возможность их выкинуть, если дико хочется.
Конкретно shared_ptr не бросает исключений почти никогда. В конструкторах они ловятся или просто пропускаются (иногда bad_alloc ещё). Единственный метод без noexcept — reset() — является сокращением для swap(), который их не бросает.
Невалидный можно вернуть разве что уже разобранным выше способом, передав конструктору указатель, а потом прибив объект напрямую через указатель. Другим путём — нет.
Yandex
Объявления
07.10.2012, 15:13     интеллектуальные указатели
Ответ Создать тему
Опции темы

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