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

Проблема с указателем на элемент вектора - C++

Восстановить пароль Регистрация
 
 
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 207
15.07.2015, 16:38     Проблема с указателем на элемент вектора #1
Всем доброго времени суток. Не могу никак выкрутиться)
Допустим, у нас есть класс "А" с параметрами:
C++
1
    std::vector <TNode*> nodes;
И есть зависимый от него класс "В" с параметрами:
C++
1
    TNode* firstNode;
В классе "В" сохранен указатель на элемент класса "А". Но элементы можно удалять независимо друг от друга. При удалении объекта класса "В" нет никаких проблем. Но при удалении объекта класса "А" (delete по вектору) указатель в классе "В" невозможно разыменовать и прога падает.
TNode:
C++
1
    int getBaseY(){return *this->baseY;}
Как быть, чет не приходят идеи в голову
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 207
16.07.2015, 00:44  [ТС]     Проблема с указателем на элемент вектора #21
Avazart, на счет не валидности хороший вариант)) такой вопрос. Указатель ведь является объектом автоматической памяти ? т.е. очистить память выделенную в одном месте можно через тот же указатель но в другом класса ?
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
16.07.2015, 01:17     Проблема с указателем на элемент вектора #22
Цитата Сообщение от Fobes Посмотреть сообщение
т.е. очистить память выделенную в одном месте можно через тот же указатель но в другом класса ?
Если мы все еще ведем речь про вектор, то нет. Ты не можешь позвать delete для определенного элемента, который лежит в векторе. Только вектор имеет право удалять свои элементы.

Добавлено через 13 минут
Цитата Сообщение от Fobes Посмотреть сообщение
А можно чуть поразвернутее про выбор именно этих умных указателе ?
Вот пример:
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 <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/make_shared.hpp>
 
 
struct Node
{
    explicit Node(boost::shared_ptr<int> & elem)
        : ref(elem)
    {}
    
    void testRef()
    {
        if(boost::shared_ptr<int> spt = ref.lock()) 
        { 
            std::cout << "Value available: " << *spt << "\n";
        }
        else 
        {
            std::cout << "Value deleted\n";
        }
    }
 
private:    
    boost::weak_ptr<int> ref;
};
 
 
int main()
{
    std::vector<boost::shared_ptr<int>> vec;
    
    vec.push_back(boost::make_shared<int>(2));
    vec.push_back(boost::make_shared<int>(3));
    vec.push_back(boost::make_shared<int>(4));
    vec.push_back(boost::make_shared<int>(5));
    
    Node node(vec[2]); // Node привязан к третьему элементу
    
    node.testRef();
    
    vec.erase(vec.begin() + 2); // удалили третий элемент
    
    node.testRef();
}
Вот тест в онлайн компиляторе: http://rextester.com/JOII1558

Но вариант я уведомлением все-таки лучше. Архитектурно.
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6167 / 2896 / 282
Регистрация: 04.12.2011
Сообщений: 7,704
Записей в блоге: 3
16.07.2015, 07:16     Проблема с указателем на элемент вектора #23
Цитата Сообщение от DrOffset Посмотреть сообщение
Если мы все еще ведем речь про вектор, то нет. Ты не можешь позвать delete для определенного элемента, который лежит в векторе. Только вектор имеет право удалять свои элементы.
Так указатель же не удаляется. Очищается память а указатель остаётся. Как граната без чеки.
Цитата Сообщение от Fobes Посмотреть сообщение
очистить память выделенную в одном месте можно через тот же указатель но в другом класса
Вы говорите "через тот же указатель ", а имеете ввиду "по тому же адресу". Да и по одному и тому же указателю из разных мест не стоило бы. Лучше всего определиться с владельцем указателя и операции захвата и освобождения больше ниоткуда не проводить. Хотя технически можно сделать и как Вы говорите.
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
16.07.2015, 08:17     Проблема с указателем на элемент вектора #24
Цитата Сообщение от IGPIGP Посмотреть сообщение
Так указатель же не удаляется.
Может быть я неверно понял вопрос ТС, но мне показалось, что он захотел переложить ответственность за удаление элементов с класса, в котором лежит вектор, на класс узла, используя при этом указатель на нужный элемент вектора. А я сказал, что память вектора принадлежит вектору и чистить ее только он и может. Если имелось в виду что-то другое, то тогда прошу прощения.
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6167 / 2896 / 282
Регистрация: 04.12.2011
Сообщений: 7,704
Записей в блоге: 3
16.07.2015, 09:01     Проблема с указателем на элемент вектора #25
Цитата Сообщение от DrOffset Посмотреть сообщение
используя при этом указатель на нужный элемент вектора
В этом случае Вы правы. А мне показалось, что речь идёт о указателях которыми заполнен вектор: TNode*
Они - в векторе класса A и еще такие же где-то ещё (в классе B) указывают на одну и ту же память. После очистки памяти через вектор к ней нельзя не обратиться ни проверить возможность доступа из класса В. Это нормально. Поэтому я и говорю, что указатель нельзя чистить где ни попадя. Хотя если отдавать его куда ни попадя, то всегда есть искушение.
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
16.07.2015, 09:12     Проблема с указателем на элемент вектора #26
Цитата Сообщение от IGPIGP Посмотреть сообщение
Поэтому я и говорю, что указатель нельзя чистить где ни попадя.
Это да. Всегда нужна продуманная стратегия владения. Если в этом вопросе хаос, то программа тоже начнет хаотично (не)работать.
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6167 / 2896 / 282
Регистрация: 04.12.2011
Сообщений: 7,704
Записей в блоге: 3
16.07.2015, 09:38     Проблема с указателем на элемент вектора #27
Цитата Сообщение от DrOffset Посмотреть сообщение
Это да.
Вот-вот. Я перечитал вопрос и понял, что я вообще ничего не понял:
Цитата Сообщение от Fobes Посмотреть сообщение
При удалении объекта класса "В" нет никаких проблем.
В этом и проблема. То есть при удалении A - delete по вектору, а при удалении B не delete по firstNode? Откуда такая дискриминация?
Надо же тоже delete, чтобы и при обращении через вектор из A всё крэшилось. Тогда может понятней будет?
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 207
16.07.2015, 10:40  [ТС]     Проблема с указателем на элемент вектора #28
IGPIGP, DrOffset, сорри, вчера уснул )) Выкрутился в общем, правда не знаю к чему это сейчас приведет, на мой взгляд все должно работать нормально. Растолкуйте, умные люди плиз)
к классу TNode добавил 2 поля:
C++
1
2
        bool valid;         //валидный ли узел
        bool connected;     //есть ли к нему подключение
При подключении провода к узлу connected выставляется в true
При удалении об А деструктор стал выглядеть так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
TObjectBase::~TObjectBase()
{
    for (unsigned int i = 0; i < nodes.size(); i++)
    {
        if (nodes[i]->connected)
        {
            nodes[i]->valid = false;
        }else{
            delete nodes[i];
        }
    }
}
т.е. мы удаляем только не подключенные узлы. Указатель в векторе ведь в автоматической памяти и они удалятся вместе с вектором, а память останется во владении указателя класса В. При удалении об В сносим оставшееся
C++
1
2
3
4
TWire::~TWire()
{
    delete firstNode, lastNode;
}
Ну и соответственно при удалении базового класса мы перестаем менять координаты таким образом:
C++
1
2
3
4
5
6
7
int TNode::getBaseX()
{
    if (this->valid) {
        X = *this->baseX;
    }
    return X;
}
Я верно мыслю или все же так лучше не делать ?
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
16.07.2015, 10:57     Проблема с указателем на элемент вектора #29
Цитата Сообщение от Fobes Посмотреть сообщение
Я верно мыслю или все же так лучше не делать ?
Ну в целом да, это как раз реализации идеи о фиктивном удалении и назначении элемента невалидным.
Только вот есть два момента. Если мы удаляем из вектора, например из середины, то адреса следующих за удаленным объектов изменятся. Если у тебя на них были подвязаны узлы, то будет ой.
Во-вторых правильно так:
C++
1
2
3
4
5
TWire::~TWire()
{
    delete firstNode;
    delete lastNode;
}
Сразу два удалить за раз нельзя
____
Поэтому, если хочешь остановиться на варианте с фиктивным удалением, то вектор уже трогать нельзя. Просто помечай элемент как удаленный, но не удаляй его по-настоящему. Либо вектор заменяй на другой контейнер, где элементы хранятся не единым блоком. Например на list. Тогда удаление одного элемента не будет влиять на другие.

Добавлено через 7 минут
Цитата Сообщение от Fobes Посмотреть сообщение
. Указатель в векторе ведь в автоматической памяти и они удалятся вместе с вектором, а память останется во владении указателя класса В.
Или у тебя в векторе уже не сами объекты лежат, а указатели на них?
Короче. Давай код что-ли, более-менее цельный. Тогда и видно будет правильно там или нет. А то гадание какое-то
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 207
16.07.2015, 11:01  [ТС]     Проблема с указателем на элемент вектора #30
DrOffset, так я же написал в первом посте) В классе А у нас вектор указателей
C++
1
std::vector <TNode*> nodes;
Мы передаем нужный нам указатель в В и там храним в виде firstNode, lastNode
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
16.07.2015, 11:02     Проблема с указателем на элемент вектора #31
Fobes, И да, вариант с умными указателями (выше пост) будет работать. Он хуже, чем некоторые другие варианты, требующие изменения архитектуры, но работать он будет.

Добавлено через 1 минуту
Цитата Сообщение от Fobes Посмотреть сообщение
Мы передаем нужный нам указатель в В и там храним в виде firstNode, lastNode
Ну если я все верно понял, то тогда у тебя вроде бы правильно (кроме попытки освободить два указателя за раз).
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 207
16.07.2015, 11:04  [ТС]     Проблема с указателем на элемент вектора #32
DrOffset, окай, с удалением учту, всем спасибо большое. Вопрос решен. ^_^
Avazart
 Аватар для Avazart
6900 / 5140 / 252
Регистрация: 10.12.2010
Сообщений: 22,587
Записей в блоге: 17
16.07.2015, 14:15     Проблема с указателем на элемент вектора #33
Если наброском как-то так:
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
class I
{
     public:
        virtual ~I(){};
        virtual void bDeleted(class B* b)= 0;
};
 
class B
{
    public:
        B():x_(0),y_(0){}
        virtual ~B()
        {
            for(size_t i=0; i<dependences_.size(); ++i)
             dependences_[i]->bDeleted(this);
        }
 
        void appendI(I* obj)
        {
            dependences_.push_back(obj);
        }
 
        void eraseI(I* obj)
        {
                std::vector<I*>::iterator it=
                    std::find(dependences_.begin(),dependences_.end(),obj);
                if(it!=dependences_.end())
                    dependences_.erase(it);
        }
 
        void setPos(int x,int y){ x_= x; y_= y; }
        int x()const{ return x_; }
        int y()const{ return y_; }
    private:
        int x_,y_;
        std::vector<I*> dependences_;
};
 
 
class A: public I
{
    public:
     A():I(){}
 
     virtual ~A()
     {
         for(size_t i=0; i<bb_.size(); ++i)
             bb_[i]->eraseI(this);
     }
 
     virtual void bDeleted(B* b)
     {
            eraseB(b);
     }
 
     void appendB(B* b)
     {
         bb_.push_back(b);
         b->appendI(this);
     }
 
     void eraseB(B* b)
     {
            std::vector<B*>::iterator i=
                std::find(bb_.begin(),bb_.end(),b);
            if(i!=bb_.end())
                bb_.erase(i);
     }
 
     const std::vector<B*>& bb()const
     {
         return bb_;
     }
 
    private:
     std::vector<B*> bb_;
};
 
 
class C: public I
{
    public:
     C():I(),b_(0){}
     virtual ~C()
     {
            if(b_) b_->eraseI(this);
     }
 
     virtual void bDeleted(B* b)
     {
            b_= 0;
     };
 
     const B* b()const
     {
         return b_;
     }
 
     void setB(B* b)
     {
         b_= b;
         b->appendI(this);
     }
 
    private:
        B* b_;
};
 
int main()
{
 
         B* b= new B;
         b->setPos(10,20);
 
         A* a= new A;
         a->appendB(b);
 
         C* c= new C;
         c->setB(b);
 
         delete b;
 
         std::cout<< a->bb().size() << std::endl;
 
         if(c->b()!=0) // b is valid pointer?
            std::cout<< c->b()->x()<<":"<< c->b()->y()<<std::endl;
         else
            std::cout<<"b deleted!"<<std::endl;
 
 
         delete a;
         delete c;
 
    getchar();
    return 0;
}
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6167 / 2896 / 282
Регистрация: 04.12.2011
Сообщений: 7,704
Записей в блоге: 3
16.07.2015, 14:31     Проблема с указателем на элемент вектора #34
Цитата Сообщение от DrOffset Посмотреть сообщение
Только вот есть два момента. Если мы удаляем из вектора, например из середины, то адреса следующих за удаленным объектов изменятся.
В векторе же указатели TNode*. Их адреса не используются. А адреса которые в них хранятся не изменяются. Хуже другое. Если в классе хранится булева переменная вроде is_valid, то где она будет когда память из под объекта освободится. Во многих тестах там где и была, но разве это путь к победе?
Тут надо указатель оборачивать чем-то, но тогда уж лучше смарт использовать какой-то.
Или сделать один класс полем другого и обращаться по указателю только через владельца. В идеале вообще не давать указатель наружу.
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
16.07.2015, 16:03     Проблема с указателем на элемент вектора #35
Цитата Сообщение от IGPIGP Посмотреть сообщение
Хуже другое. Если в классе хранится булева переменная вроде is_valid, то где она будет когда память из под объекта освободится.
Возможно у автора ошибки в его коде. Но я без полной картины не могу сделать точных выводов. Да и не особо хочется. Неблагодарное это занятие, как правило

Цитата Сообщение от IGPIGP Посмотреть сообщение
В векторе же указатели TNode*.
Да вот фиг его знает. Он ссылается из Node на какие-то инты. А где эти инты лежат, мне сперва было не понятно. Вот я и подумал, что в векторе другом
Avazart
 Аватар для Avazart
6900 / 5140 / 252
Регистрация: 10.12.2010
Сообщений: 22,587
Записей в блоге: 17
16.07.2015, 16:16     Проблема с указателем на элемент вектора #36
Цитата Сообщение от DrOffset Посмотреть сообщение
C++
1
if(boost::shared_ptr<int> spt = ref.lock())/*   "=" ?? */
Опечатка или Си-стайЛ?
DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
16.07.2015, 16:23     Проблема с указателем на элемент вектора #37
Цитата Сообщение от Avazart Посмотреть сообщение
Опечатка или Си-стайЛ?
Нет, тут как раз все правильно. Причем такое писать можно только в С++ (объявление переменных в условии if).
В этом выражении после конструирования переменной spt, у нее будет вызван operator bool(), ну и соответственно произведена проверка.
Avazart
16.07.2015, 16:26
  #38

Не по теме:

Значит стайл ...

C
1
2
3
4
5
6
FILE *fp;
if((fp=fopen("test", "rb+"))==NULL) 
{
  printf("He удается открыть файл.\n");
  exit(1);
}

DrOffset
6426 / 3800 / 880
Регистрация: 30.01.2014
Сообщений: 6,594
16.07.2015, 16:34     Проблема с указателем на элемент вектора #39

Не по теме:

Цитата Сообщение от Avazart Посмотреть сообщение
Значит Си стайл ...
Поясни?


Добавлено через 7 минут

Не по теме:

Avazart, ты путаешь. Мой код и твой - разные. Тут где-то на форуме проскакивал вопрос из книги Страуструпа с таким же кодом. Суть этого в том, чтобы объявлять переменные там, где они используются и сразу инициализировать их. В данном случае spt имеет смысл только внутри if и его область видимости ограничена скобками if. Это чисто С++сный подход. В этом случае = - это не присваивание, а инициализация. Т.е. здесь работает конструктор. Поэтому этот код не вызовет у компилятора никаких предупреждений.

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.07.2015, 16:34     Проблема с указателем на элемент вектора
Еще ссылки по теме:

В чем разница между указателем и указателем на указатель? C++
C++ Проблема с указателем на функцию

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

Или воспользуйтесь поиском по форуму:
Avazart
16.07.2015, 16:34     Проблема с указателем на элемент вектора
  #40

Не по теме:

Че не понятно... плохая практика в условиях использовать присваивание, плохо читается = / == .

Yandex
Объявления
16.07.2015, 16:34     Проблема с указателем на элемент вектора
Ответ Создать тему
Опции темы

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