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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 17, средняя оценка - 4.71
AnreyKazakov
Заблокирован
#1

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

07.10.2012, 00:39. Просмотров 2442. Ответов 20
Метки нет (Все метки)

Блин, не совсем понял зачем такой геморой нужен как эти указатели, но фиг с ним вопрос основной по коду, вот сделал по примеру с учебника, может есть косяки, вопросы выделил комментариями...
примкр класса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
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.10.2012, 00:39
Здравствуйте! Я подобрал для вас темы с ответами на вопрос интеллектуальные указатели (C++):

Указатели и указатели на указатели, а также типы данных - C++
Недавно начал изучать Си, перешел с Delphi. Много непонятного и пока процесс идет медленно. Накачал литературы, буду изучать) Щас...

Через указатели на указатели посчитать сумму двух чисел и записать в третье - C++
1. Через указатели на указатели посчитать сумму двух чисел и записать в третье. 2. Написать примитивный калькулятор, пользуясь только...

Есть три переменные. Используя указатели на указатели, поменять значение максимальной и минимальной переменной - C++
Мой код. #include &lt;iostream&gt; #include &lt;stdlib.h&gt; #include&lt;iomanip&gt; using namespace std; void min_max(int*pa, int*pb,...

Указатели на указатели с числами. Почему можно присвоить число в 4-ый элемент, если массив из 2 элементов? - C++
Есть массив int **mas; mas=new int*; // выделил место под пять строк, верно ? mas=new int;// выделил для первой строки матрицы два...

Отсортировать массив и вывести на экран (массивы и указатели на указатели) - C++
Даны массивы F-фамилий студентов и S-результаты сессии (5 оценок) , причем s- результат сессии F студента. Отсортировать массив S по...

Указатели на слонов или А зачем нужны указатели? - C++
Знаю что таких вопросов было уйма, но я так и не нашел ответа на свой вопрос. Для чего нужны указатели? Что такое указатели я знаю, это...

20
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
07.10.2012, 00:42 #2
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Задача всех этих умных указателей: облегчить менеджмент памяти в случаях, когда владение указателями не сосредоточено где-то в одном месте, а может передаваться, разделятся и тому подобное. Естественно, всё это ценой определённой потери в скорости. Она не особо критична, но всё же есть.

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

Если аккуратно следить за передачей владения объектами, вполне можно обойтись и без них. Но не у всех достаточно мозгов/терпения/времени, чтобы следить вручную/тщательно прорабатывать архитектуру и т. п.
3
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 Правильны ли суждения мои?
0
BRcr
4008 / 2297 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
07.10.2012, 10:31 #4
Ты упускаешь одну очень важную вещь - при использовании умных указателей отпадает необходимость явно освобождать память динамически созданных объектов. Пока они нужны - они существуют, как только все копии указателя обнулились, память освобождается. Просто и ни о чем заботиться не надо.
Серьезный недостаток лишь один, это быстродействие. В алгоритмах, чувствительных к скорости умные указатели применять обычно нецелесообразно, так как они выполняют относительно избыточную работу.
1
soon
2542 / 1307 / 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;
}
1
AnreyKazakov
Заблокирован
07.10.2012, 10:36  [ТС] #6
Цитата Сообщение от BRcr Посмотреть сообщение
при использовании умных указателей отпадает необходимость явно освобождать память динамически созданных объектов
Покажите, пожалуйста, какой-нибудь простенький пример, бошка уже трещит будто с похмелья =(
0
BRcr
4008 / 2297 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
07.10.2012, 10:53 #7
Куда уж проще - создаешь указатель, суешь ему адрес динамически созданного и забываешь.
Это чрезвычайно удобно с теми типами данных, что нельзя создавать статически, например, классы библиотеки VCL.
C++
1
std::auto_prt<TStringList> ptr( new TStringList( ) );
Можно делать их членами классов, тогда время жизни объекта будет либо совпадать с временем жизни экземпляра класса, либо, если указатель был скопирован, до момента разрушения его копии. Пока жив хоть один указатель, жив и объект.
1
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;
    }
В этом примере память потеряется или нет?
0
soon
2542 / 1307 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
07.10.2012, 11:28 #9
Цитата Сообщение от AnreyKazakov Посмотреть сообщение
В этом примере память потеряется
Разумеется
1
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;
        }
0
BRcr
4008 / 2297 / 155
Регистрация: 03.02.2011
Сообщений: 5,064
Записей в блоге: 10
07.10.2012, 12:56 #11
Цитата Сообщение от AnreyKazakov Посмотреть сообщение
что же будет показывать указатель, кот показывает на объект, который был удален?
Мусор в лучшем случае, access violation в худшем.
1
Jupiter
Каратель
Эксперт С++
6559 / 3980 / 227
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
07.10.2012, 13:00 #12
Цитата Сообщение от BRcr Посмотреть сообщение
Мусор в лучшем случае, access violation в худшем.
как раз таки наоборот, access violation в лучшем случае ибо ошибка будет выявлена
1
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
07.10.2012, 13:32 #13
Цитата Сообщение от AnreyKazakov Посмотреть сообщение
Т.е. если применять в классе обычные указатели, тк в конце обязательно нужно delete в деструктор пихать, то в процессе освобождения объектами этого класса памяти указатель будет удалятся.... что же будет показывать указатель, кот показывает на объект, который был удален?
Будет показывать "чёрти куда". Вот именно от этого немного защищают умные указатели: они не будут гадить память, они не заставят ОС прибить процесс из-за сегфолта. Они хотя бы выкинут исключение, которое можно обработать самостоятельно и попытаться восстановить работу (ну или хотя бы сохранить что можно куда-нибудь), а не просто пустить сегфолт на самотёк и заставить пользователя наложить в штаны от выпрыгивающего окошка про «ПАМЯТЬ НЕ МОЖЕТ БЫТЬ READ, приложение будет ЗАКРЫТО, а документ, над которым вы работали ТРИ ЧАСА и НЕ СОХРАНЯЛИСЬ, будет УДАЛЁН, мвахаха, обратитесь с жалобой и вот этим дампом памяти к разработчику».

Цитата Сообщение от AnreyKazakov Посмотреть сообщение
И еще кусок кода с учебника, кот опис класс, не могу понять его (сверху в 1 сообщ весь код)
Я вообще не понимаю, зачем там хранится и указатель, и значение. Вы точно уверены, что это smart pointer, а не что-то другое? То, что ix — это тот самый счётчик, очевидно. Вопрос, какого чёрта его дёргают туда-сюда, да ещё и в классе point. Это тайна для меня.
1
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 Посмотреть сообщение
удалить этот объект
зачем его удалять?
0
OhMyGodSoLong
~ Эврика! ~
1244 / 993 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
07.10.2012, 14:29 #15
Оно как минимум неочевидно. Можете бросить яблоком в того, откуда копировали.

Идея в том, что указатель из rhs замещает указатель из this. Следовательно, количество ссылок на объект, на который ссылается rhs, увеличивается на единицу, а тот объект, на который до operator= ссылался this, теряет одну ссылку. Соответственно, если на него больше никто не ссылается, то его можно удалить.
1
07.10.2012, 14:29
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.10.2012, 14:29
Привет! Вот еще темы с ответами:

Написать программу сортировки через указатели на указатели - C++
Вот моя программа #include &lt;iostream&gt; #include &lt;conio.h&gt; #include &lt;string&gt; using namespace std; //Сортировка &quot;пузырьком&quot;. ...

Используются ли на практике указатели на указатели объектов? - C++
Имеются ввиду указатели именно на объекты, а не динамические массивы. Например такой: Object** obj; А как насчёт такого: Object***...

Указатели и массивы. Указатели и функции - C++
Никак не разберусь с указателями на функцию. Пишу в Visual Studio. Надо написать функцию Compress() с использованием указателей, которая...

Указатели на массивы. Указатели и функции - C++
Вот задача: Даны два массива : А и B. Необходимо создать третий массив, в котором нужно собрать: -Элементы обоих массивов; -Общие...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru