Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 5.00/13: Рейтинг темы: голосов - 13, средняя оценка - 5.00
17 / 17 / 5
Регистрация: 19.09.2012
Сообщений: 216

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

15.07.2015, 16:38. Показов 3573. Ответов 54
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем доброго времени суток. Не могу никак выкрутиться)
Допустим, у нас есть класс "А" с параметрами:
C++
1
    std::vector <TNode*> nodes;
И есть зависимый от него класс "В" с параметрами:
C++
1
    TNode* firstNode;
В классе "В" сохранен указатель на элемент класса "А". Но элементы можно удалять независимо друг от друга. При удалении объекта класса "В" нет никаких проблем. Но при удалении объекта класса "А" (delete по вектору) указатель в классе "В" невозможно разыменовать и прога падает.
TNode:
C++
1
    int getBaseY(){return *this->baseY;}
Как быть, чет не приходят идеи в голову
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.07.2015, 16:38
Ответы с готовыми решениями:

Как правильно обратиться к элементам полиморфного вектора (с умным указателем)?
Здравствуйте, по заданию нужно: создать абстрактный класс с функцией - норма, определить функцию для производных классов, создать в...

Проблема с указателем на функцию
Доброго времени суток, пишу приложение, которое реализует все функции АТД (двусвязный список). Есть стандартная библиотека, есть функция...

Проблема с указателем мыши
Указатель мыши в AltLinux5.0 при запуске убегает в левый верхний угол и категорически не желает оттуда уходить. На компе две системы -...

54
17 / 17 / 5
Регистрация: 19.09.2012
Сообщений: 216
16.07.2015, 00:44  [ТС]
Студворк — интернет-сервис помощи студентам
Avazart, на счет не валидности хороший вариант)) такой вопрос. Указатель ведь является объектом автоматической памяти ? т.е. очистить память выделенную в одном месте можно через тот же указатель но в другом класса ?
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
16.07.2015, 01:17
Цитата Сообщение от 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

Но вариант я уведомлением все-таки лучше. Архитектурно.
2
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
16.07.2015, 07:16
Цитата Сообщение от DrOffset Посмотреть сообщение
Если мы все еще ведем речь про вектор, то нет. Ты не можешь позвать delete для определенного элемента, который лежит в векторе. Только вектор имеет право удалять свои элементы.
Так указатель же не удаляется. Очищается память а указатель остаётся. Как граната без чеки.
Цитата Сообщение от Fobes Посмотреть сообщение
очистить память выделенную в одном месте можно через тот же указатель но в другом класса
Вы говорите "через тот же указатель ", а имеете ввиду "по тому же адресу". Да и по одному и тому же указателю из разных мест не стоило бы. Лучше всего определиться с владельцем указателя и операции захвата и освобождения больше ниоткуда не проводить. Хотя технически можно сделать и как Вы говорите.
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
16.07.2015, 08:17
Цитата Сообщение от IGPIGP Посмотреть сообщение
Так указатель же не удаляется.
Может быть я неверно понял вопрос ТС, но мне показалось, что он захотел переложить ответственность за удаление элементов с класса, в котором лежит вектор, на класс узла, используя при этом указатель на нужный элемент вектора. А я сказал, что память вектора принадлежит вектору и чистить ее только он и может. Если имелось в виду что-то другое, то тогда прошу прощения.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
16.07.2015, 09:01
Цитата Сообщение от DrOffset Посмотреть сообщение
используя при этом указатель на нужный элемент вектора
В этом случае Вы правы. А мне показалось, что речь идёт о указателях которыми заполнен вектор: TNode*
Они - в векторе класса A и еще такие же где-то ещё (в классе B) указывают на одну и ту же память. После очистки памяти через вектор к ней нельзя не обратиться ни проверить возможность доступа из класса В. Это нормально. Поэтому я и говорю, что указатель нельзя чистить где ни попадя. Хотя если отдавать его куда ни попадя, то всегда есть искушение.
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
16.07.2015, 09:12
Цитата Сообщение от IGPIGP Посмотреть сообщение
Поэтому я и говорю, что указатель нельзя чистить где ни попадя.
Это да. Всегда нужна продуманная стратегия владения. Если в этом вопросе хаос, то программа тоже начнет хаотично (не)работать.
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
16.07.2015, 09:38
Цитата Сообщение от DrOffset Посмотреть сообщение
Это да.
Вот-вот. Я перечитал вопрос и понял, что я вообще ничего не понял:
Цитата Сообщение от Fobes Посмотреть сообщение
При удалении объекта класса "В" нет никаких проблем.
В этом и проблема. То есть при удалении A - delete по вектору, а при удалении B не delete по firstNode? Откуда такая дискриминация?
Надо же тоже delete, чтобы и при обращении через вектор из A всё крэшилось. Тогда может понятней будет?
0
17 / 17 / 5
Регистрация: 19.09.2012
Сообщений: 216
16.07.2015, 10:40  [ТС]
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;
}
Я верно мыслю или все же так лучше не делать ?
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
16.07.2015, 10:57
Цитата Сообщение от Fobes Посмотреть сообщение
Я верно мыслю или все же так лучше не делать ?
Ну в целом да, это как раз реализации идеи о фиктивном удалении и назначении элемента невалидным.
Только вот есть два момента. Если мы удаляем из вектора, например из середины, то адреса следующих за удаленным объектов изменятся. Если у тебя на них были подвязаны узлы, то будет ой.
Во-вторых правильно так:
C++
1
2
3
4
5
TWire::~TWire()
{
    delete firstNode;
    delete lastNode;
}
Сразу два удалить за раз нельзя
____
Поэтому, если хочешь остановиться на варианте с фиктивным удалением, то вектор уже трогать нельзя. Просто помечай элемент как удаленный, но не удаляй его по-настоящему. Либо вектор заменяй на другой контейнер, где элементы хранятся не единым блоком. Например на list. Тогда удаление одного элемента не будет влиять на другие.

Добавлено через 7 минут
Цитата Сообщение от Fobes Посмотреть сообщение
. Указатель в векторе ведь в автоматической памяти и они удалятся вместе с вектором, а память останется во владении указателя класса В.
Или у тебя в векторе уже не сами объекты лежат, а указатели на них?
Короче. Давай код что-ли, более-менее цельный. Тогда и видно будет правильно там или нет. А то гадание какое-то
1
17 / 17 / 5
Регистрация: 19.09.2012
Сообщений: 216
16.07.2015, 11:01  [ТС]
DrOffset, так я же написал в первом посте) В классе А у нас вектор указателей
C++
1
std::vector <TNode*> nodes;
Мы передаем нужный нам указатель в В и там храним в виде firstNode, lastNode
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
16.07.2015, 11:02
Fobes, И да, вариант с умными указателями (выше пост) будет работать. Он хуже, чем некоторые другие варианты, требующие изменения архитектуры, но работать он будет.

Добавлено через 1 минуту
Цитата Сообщение от Fobes Посмотреть сообщение
Мы передаем нужный нам указатель в В и там храним в виде firstNode, lastNode
Ну если я все верно понял, то тогда у тебя вроде бы правильно (кроме попытки освободить два указателя за раз).
0
17 / 17 / 5
Регистрация: 19.09.2012
Сообщений: 216
16.07.2015, 11:04  [ТС]
DrOffset, окай, с удалением учту, всем спасибо большое. Вопрос решен. ^_^
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
16.07.2015, 14:15
Если наброском как-то так:
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;
}
1
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
16.07.2015, 14:31
Цитата Сообщение от DrOffset Посмотреть сообщение
Только вот есть два момента. Если мы удаляем из вектора, например из середины, то адреса следующих за удаленным объектов изменятся.
В векторе же указатели TNode*. Их адреса не используются. А адреса которые в них хранятся не изменяются. Хуже другое. Если в классе хранится булева переменная вроде is_valid, то где она будет когда память из под объекта освободится. Во многих тестах там где и была, но разве это путь к победе?
Тут надо указатель оборачивать чем-то, но тогда уж лучше смарт использовать какой-то.
Или сделать один класс полем другого и обращаться по указателю только через владельца. В идеале вообще не давать указатель наружу.
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
16.07.2015, 16:03
Цитата Сообщение от IGPIGP Посмотреть сообщение
Хуже другое. Если в классе хранится булева переменная вроде is_valid, то где она будет когда память из под объекта освободится.
Возможно у автора ошибки в его коде. Но я без полной картины не могу сделать точных выводов. Да и не особо хочется. Неблагодарное это занятие, как правило

Цитата Сообщение от IGPIGP Посмотреть сообщение
В векторе же указатели TNode*.
Да вот фиг его знает. Он ссылается из Node на какие-то инты. А где эти инты лежат, мне сперва было не понятно. Вот я и подумал, что в векторе другом
0
Эксперт С++
 Аватар для Avazart
8489 / 6156 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
16.07.2015, 16:16
Цитата Сообщение от DrOffset Посмотреть сообщение
C++
1
if(boost::shared_ptr<int> spt = ref.lock())/*   "=" ?? */
Опечатка или Си-стайЛ?
0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
16.07.2015, 16:23
Цитата Сообщение от Avazart Посмотреть сообщение
Опечатка или Си-стайЛ?
Нет, тут как раз все правильно. Причем такое писать можно только в С++ (объявление переменных в условии if).
В этом выражении после конструирования переменной spt, у нее будет вызван operator bool(), ну и соответственно произведена проверка.
0
16.07.2015, 16:26

Не по теме:

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

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

0
19501 / 10106 / 2461
Регистрация: 30.01.2014
Сообщений: 17,825
16.07.2015, 16:34

Не по теме:

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


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

Не по теме:

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

0
16.07.2015, 16:34

Не по теме:

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

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
16.07.2015, 16:34

Проблема с указателем на строку
Пишу класс Строка на Visual Studio. Проблема с функцией-оператором + ( Он у меня только на добавление символа, так как мне большего на...

Проблема с умным указателем std::unique_ptr
здравствуйте. есть задание - написать небольшую простенькую игру, где есть базовый класс Unit, кроме него есть ещё три класса -...

Заменить максимальный элемент изначального вектора на первый минимальный элемент изначального вектора
Здравствуйте, помогите составить программу по обработке вектора в Mathcad 15. Необходимо вектор из 5 элементов (5 0 -1 13 -7)...

Список с указателем на последний элемент
Приветствую. Есть циклический односвязный список с зацикливанием через голову. Требуется: убрать зацикливание через голову, а...

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


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Doom для терминала без стрельбы и монстров. 3D Raycasting на ascii.
dcc0 05.07.2026
Попросил нейронную сеть deepai. org написать рейкастинг 3D с библиотекой ncurses для Linux. Чтобы можно было ходить на стрелочки. Чтобы стены были отрисованы символами. Справилась. Первый вариант. . .
Установка статуса документа по условию
Maks 05.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "НарядПутевка" разработанного в КА2. Задача: в табличной части "Материалы" документа при записи автоматически устанавливать статус. . .
Сезонность и суточность закисления почв
anaschu 04.07.2026
200 часов это все равно моловато. Есть ситуации, но нестандартные, когда смена происходит за 5 лет. Но обычно это 50 лет и более. Наверное, закисление почвы происходит сезонно в средней. . .
В чем ценность человеческого опыта в глобальном смысле?
kumehtar 03.07.2026
Возможно, ценность человека не в том, что он однажды достигает мудрости, а в том, что он становится носителем карты пути. Он знает не только истину, но и последовательность внутренних изменений,. . .
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи. Через несколько переработок от PHP кода к C89 (надеюсь, 89). Но довольно запутанно получилось. Код для Linux. Но если убрать time и то, что с ним. . .
Сам себя обучал rest api
anaschu 02.07.2026
Педагогический лайфхак: Почему чистый REST API для ученика намного круче, чем готовые библиотеки Когда мы отказались от капризного JAR-файла AnyLogic и переписали код на стандартный HttpClient,. . .
rest api anylogic - выполнение модели на своём русском сайте
anaschu 02.07.2026
Как подружиться с AnyLogic Cloud API, победить провайдеров и развернуться Java-бэкенд в Docker на бесплатном хостинге: Двухдневный лог борьбы Всем привет! Хочу поделиться свежим (и довольно. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru