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

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

Войти
Регистрация
Восстановить пароль
 
 
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 212
#1

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

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

Всем доброго времени суток. Не могу никак выкрутиться)
Допустим, у нас есть класс "А" с параметрами:
C++
1
    std::vector <TNode*> nodes;
И есть зависимый от него класс "В" с параметрами:
C++
1
    TNode* firstNode;
В классе "В" сохранен указатель на элемент класса "А". Но элементы можно удалять независимо друг от друга. При удалении объекта класса "В" нет никаких проблем. Но при удалении объекта класса "А" (delete по вектору) указатель в классе "В" невозможно разыменовать и прога падает.
TNode:
C++
1
    int getBaseY(){return *this->baseY;}
Как быть, чет не приходят идеи в голову
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.07.2015, 16:38
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Проблема с указателем на элемент вектора (C++):

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

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

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

Определить количество положительных элементов вектора С(10) и заменить этим значением минимальный элемент вектора А(5) - C++
Ребята помогите пожалуйста с задачкой. Я сам не шарю в C++, но в этом семестре появился этот предмет! И завтра его надо будет сдать :( Буду...

В чем разница между указателем и указателем на указатель? - C++
int x, *p, *q; x=10; p=&amp;x; q=p; cout&lt;&lt;*q; int x, *p, **q; x=10; p=&amp;x; q=&amp;p;

Изменение вектора. Наибольший элемент вектора - C++
Добрый день, нужна оценка кода. Пропустил занятия, делал по теории, опирался на массивы. Скажите, правильно ли реализовано? Создать...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Avazart
Эксперт С++
7191 / 5365 / 280
Регистрация: 10.12.2010
Сообщений: 23,674
Записей в блоге: 17
16.07.2015, 00:09 #16
Цитата Сообщение от DrOffset Посмотреть сообщение
Лучше хранить индекс элемента из вектора, а не указатели.
И чем это поможет?
Абсолютно ничем, получите невалидный индекс вместо невалидного указателя.

Добавлено через 1 минуту
Умные же указатели- тоже не подходят так как не решат проблему согласования, ибо просто не удалят элемент.
0
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 212
16.07.2015, 00:10  [ТС] #17
Avazart, как же быть то тогда ?
0
Avazart
Эксперт С++
7191 / 5365 / 280
Регистрация: 10.12.2010
Сообщений: 23,674
Записей в блоге: 17
16.07.2015, 00:23 #18
Цитата Сообщение от Fobes Посмотреть сообщение
как отловить момент удаления из класса "В"
Класс B должен "извещать" из своего деструктора все зависимые классы об своем удалении.

Есть другой вариант не удалять объект вообще а просто помечать его "невалидным" и действовать как будто его нет, самое просто, но ценой памяти.
0
DrOffset
7154 / 4295 / 969
Регистрация: 30.01.2014
Сообщений: 7,099
16.07.2015, 00:26 #19
Цитата Сообщение от Avazart Посмотреть сообщение
И чем это поможет?
Невалидный индекс хотя бы можно проверить. Битый указатель же не проверишь уже точно.
Цитата Сообщение от Avazart Посмотреть сообщение
Умные же указатели- тоже не подходят так как не решат проблему согласования, ибо просто не удалят элемент.
Вообще все эти советы были даны исходя из того, что автор хочет отделаться малой кровью. Не переписывать код. Естественно, правильным подходом было перепроектировать и переписать код полностью. В том числе с учетом твоих замечаний по поводу извещения об удалении, с которыми я полностью согласен.
0
Avazart
Эксперт С++
7191 / 5365 / 280
Регистрация: 10.12.2010
Сообщений: 23,674
Записей в блоге: 17
16.07.2015, 00:28 #20
Цитата Сообщение от DrOffset Посмотреть сообщение
Невалидный индекс хотя бы можно проверить.
Мм и каким чудом?
Куда будет указывать индекс после удаления? На другой элемент?
1
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 212
16.07.2015, 00:44  [ТС] #21
Avazart, на счет не валидности хороший вариант)) такой вопрос. Указатель ведь является объектом автоматической памяти ? т.е. очистить память выделенную в одном месте можно через тот же указатель но в другом класса ?
0
DrOffset
7154 / 4295 / 969
Регистрация: 30.01.2014
Сообщений: 7,099
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

Но вариант я уведомлением все-таки лучше. Архитектурно.
2
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6472 / 3120 / 306
Регистрация: 04.12.2011
Сообщений: 8,594
Записей в блоге: 4
16.07.2015, 07:16 #23
Цитата Сообщение от DrOffset Посмотреть сообщение
Если мы все еще ведем речь про вектор, то нет. Ты не можешь позвать delete для определенного элемента, который лежит в векторе. Только вектор имеет право удалять свои элементы.
Так указатель же не удаляется. Очищается память а указатель остаётся. Как граната без чеки.
Цитата Сообщение от Fobes Посмотреть сообщение
очистить память выделенную в одном месте можно через тот же указатель но в другом класса
Вы говорите "через тот же указатель ", а имеете ввиду "по тому же адресу". Да и по одному и тому же указателю из разных мест не стоило бы. Лучше всего определиться с владельцем указателя и операции захвата и освобождения больше ниоткуда не проводить. Хотя технически можно сделать и как Вы говорите.
0
DrOffset
7154 / 4295 / 969
Регистрация: 30.01.2014
Сообщений: 7,099
16.07.2015, 08:17 #24
Цитата Сообщение от IGPIGP Посмотреть сообщение
Так указатель же не удаляется.
Может быть я неверно понял вопрос ТС, но мне показалось, что он захотел переложить ответственность за удаление элементов с класса, в котором лежит вектор, на класс узла, используя при этом указатель на нужный элемент вектора. А я сказал, что память вектора принадлежит вектору и чистить ее только он и может. Если имелось в виду что-то другое, то тогда прошу прощения.
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6472 / 3120 / 306
Регистрация: 04.12.2011
Сообщений: 8,594
Записей в блоге: 4
16.07.2015, 09:01 #25
Цитата Сообщение от DrOffset Посмотреть сообщение
используя при этом указатель на нужный элемент вектора
В этом случае Вы правы. А мне показалось, что речь идёт о указателях которыми заполнен вектор: TNode*
Они - в векторе класса A и еще такие же где-то ещё (в классе B) указывают на одну и ту же память. После очистки памяти через вектор к ней нельзя не обратиться ни проверить возможность доступа из класса В. Это нормально. Поэтому я и говорю, что указатель нельзя чистить где ни попадя. Хотя если отдавать его куда ни попадя, то всегда есть искушение.
0
DrOffset
7154 / 4295 / 969
Регистрация: 30.01.2014
Сообщений: 7,099
16.07.2015, 09:12 #26
Цитата Сообщение от IGPIGP Посмотреть сообщение
Поэтому я и говорю, что указатель нельзя чистить где ни попадя.
Это да. Всегда нужна продуманная стратегия владения. Если в этом вопросе хаос, то программа тоже начнет хаотично (не)работать.
1
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6472 / 3120 / 306
Регистрация: 04.12.2011
Сообщений: 8,594
Записей в блоге: 4
16.07.2015, 09:38 #27
Цитата Сообщение от DrOffset Посмотреть сообщение
Это да.
Вот-вот. Я перечитал вопрос и понял, что я вообще ничего не понял:
Цитата Сообщение от Fobes Посмотреть сообщение
При удалении объекта класса "В" нет никаких проблем.
В этом и проблема. То есть при удалении A - delete по вектору, а при удалении B не delete по firstNode? Откуда такая дискриминация?
Надо же тоже delete, чтобы и при обращении через вектор из A всё крэшилось. Тогда может понятней будет?
0
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 212
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;
}
Я верно мыслю или все же так лучше не делать ?
0
DrOffset
7154 / 4295 / 969
Регистрация: 30.01.2014
Сообщений: 7,099
16.07.2015, 10:57 #29
Цитата Сообщение от Fobes Посмотреть сообщение
Я верно мыслю или все же так лучше не делать ?
Ну в целом да, это как раз реализации идеи о фиктивном удалении и назначении элемента невалидным.
Только вот есть два момента. Если мы удаляем из вектора, например из середины, то адреса следующих за удаленным объектов изменятся. Если у тебя на них были подвязаны узлы, то будет ой.
Во-вторых правильно так:
C++
1
2
3
4
5
TWire::~TWire()
{
    delete firstNode;
    delete lastNode;
}
Сразу два удалить за раз нельзя
____
Поэтому, если хочешь остановиться на варианте с фиктивным удалением, то вектор уже трогать нельзя. Просто помечай элемент как удаленный, но не удаляй его по-настоящему. Либо вектор заменяй на другой контейнер, где элементы хранятся не единым блоком. Например на list. Тогда удаление одного элемента не будет влиять на другие.

Добавлено через 7 минут
Цитата Сообщение от Fobes Посмотреть сообщение
. Указатель в векторе ведь в автоматической памяти и они удалятся вместе с вектором, а память останется во владении указателя класса В.
Или у тебя в векторе уже не сами объекты лежат, а указатели на них?
Короче. Давай код что-ли, более-менее цельный. Тогда и видно будет правильно там или нет. А то гадание какое-то
1
Fobes
16 / 16 / 2
Регистрация: 19.09.2012
Сообщений: 212
16.07.2015, 11:01  [ТС] #30
DrOffset, так я же написал в первом посте) В классе А у нас вектор указателей
C++
1
std::vector <TNode*> nodes;
Мы передаем нужный нам указатель в В и там храним в виде firstNode, lastNode
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.07.2015, 11:01
Привет! Вот еще темы с ответами:

Пользуясь указателем на массив целых чисел, найти минимальный и максимальный элемент массива - C++
Пользуясь указателем на массив целых чисел, найти минимальный и максимальный элемент массива. Использовать в программе арифметику...

Переделать функцию c указателем на int, на функцию с указателем на void - C++
Есть рабочий код qsort для int: void qsort(int *base, int n) { // Прекратить если количество элементов меньше либо равно единице....

Наибольший элемент вектора - C++
Помогите, пожалуйста разобраться с ошибкой. Прога-ма запрашивает числа, записывает в вектор, находит самое большое число и выводит его на...

Извлечь элемент из вектора - C++
Пожалуйста, помогите разобраться. Это функция разбивки строки на лексемы, и копирования результатов разбивки в вектор. void...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
16.07.2015, 11:01
Ответ Создать тему
Опции темы

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