Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.55/11: Рейтинг темы: голосов - 11, средняя оценка - 4.55
6 / 6 / 1
Регистрация: 09.02.2016
Сообщений: 296

Странное поведение указателя

07.09.2024, 12:39. Показов 2295. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день!
Есть такой кусок кода. В качестве параметра в данный метод передается указатель на вектор, размером 7 элементов. После приравнивания я ожидаю, что _outputs->size(); и outputs->size(); будут иметь одинаковый размер, но по факту получается ерунда.
Кто может подсказать в чем проблема, бьюсь несколько часов уже.

.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    class OutputSignals {
        private:
            static inline const std::string curClassName = "OutputSignals";
 
            using IsxExtensionsCommon = Libs::Isx::Extensions::Common;
 
            std::vector<IsxExtensionsCommon::PortPin> *_outputs;
            GPIO_PinState _outputsOn;
            GPIO_PinState _outputsOff;
 
            void outputSetOn(IsxExtensionsCommon::PortPin &portPin);
            void outputSetOff(IsxExtensionsCommon::PortPin &portPin);
...................
 
    };
Миниатюры
Странное поведение указателя  
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
07.09.2024, 12:39
Ответы с готовыми решениями:

Странное поведение указателя
class XMLDocument { public: char *xml; XMLDocument() { }; void NewXML()

Странное поведение bool
Помогал отлаживать код и мы наткнулись на удивительное. Кодер скрыл отображение варнингов в VS2010. Метод М1 не всегда возвращал...

Странное поведение функции sscanf_s !
Всем доброго времени суток ! Пытаюсь выделить из строки нужные данные при помощи &quot;маски&quot; функцией sscanf_s, но при...

14
фрилансер
 Аватар для Алексей1153
6467 / 5682 / 1131
Регистрация: 11.10.2019
Сообщений: 15,145
07.09.2024, 13:38
a13428711, а вот так что говорит?

нужен заголовок <cassert>
C++
1
assert(_outputs->size()==outputs->size());
Добавлено через 1 минуту
кстати, а зачем это насильное приведение к int, используй size_t
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
07.09.2024, 14:12
a13428711, а вы знаете про правило Трех/Пяти/Нуля ?

Добавлено через 6 минут
a13428711, то что вы наблюдаете, вероятно проявление UB, то есть, указатель уже не валидный пришел в функцию на скриншоте.
Ищите ошибку ранее по вызовам.
0
6 / 6 / 1
Регистрация: 09.02.2016
Сообщений: 296
07.09.2024, 14:28  [ТС]
SmallEvil, да не, первый size же нормально отработал, добавленные в вектор элементы есть если в отладчике глянуть

Добавлено через 10 минут
Алексей1153, вернусь домой гляну.
А приведение это на время отладки, я уже на всё погрешить успел)
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
07.09.2024, 14:43
Цитата Сообщение от a13428711 Посмотреть сообщение
да не, первый size же нормально отработал
Почему вы так решили ? Потому что размер случайно совпал ?
То есть вы не доверяете моему мнению и уверены что между одним вызовом size и другим случилась магия ?
Ну тогда ищите-свищите
Кто ж вам доктор.

Добавлено через 1 минуту
Цитата Сообщение от a13428711 Посмотреть сообщение
добавленные в вектор элементы есть если в отладчике глянуть
После уничтожения объекта никто спецом не будет очищать ваши данные.
Они могут просто лежать, пока та область памяти никому не понадобится.
0
6 / 6 / 1
Регистрация: 09.02.2016
Сообщений: 296
07.09.2024, 15:45  [ТС]
SmallEvil, Можно по сути проверит адрес на момент создания и на момент присвоения, совпадают или нет. Или как?
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
07.09.2024, 16:02
Цитата Сообщение от a13428711 Посмотреть сообщение
Можно по сути проверит адрес на момент создания и на момент присвоения, совпадают или нет. Или как?
Адресы будут совпадать, куда им деваться, но самого объекта уже нет, там лежит его труп.
1. Проверьте на соблюдение правила Трех/Пяти.
2. Проверьте время жизни ваших объектов. Кто где создавался и кто, кем, где и когда уничтожается.

Просто в коде, этого нельзя сделать, только обертки с логированием.

Добавлено через 3 минуты
Я надеюсь у вас всё в одном потоке выполняется ?

Добавлено через 1 минуту
И для практического использования, для всех не низкоуровневых классов откажитесь от сырых указателей.
Замените их умными указателями.
0
6 / 6 / 1
Регистрация: 09.02.2016
Сообщений: 296
07.09.2024, 18:39  [ТС]
SmallEvil, но если самого объекта нет, то я же не смог бы обратиться к нему через size()?
Я не критикую, просто хочу докопаться до истины - непривычно после шарпа работать таким образом с классами, а в чистом С с такими приколами не сталкивался. С плюсами третий день работаю.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
07.09.2024, 20:19
Цитата Сообщение от a13428711 Посмотреть сообщение
но если самого объекта нет, то я же не смог бы обратиться к нему через size()?
смог бы, с некоторой долей вероятности
Цитата Сообщение от a13428711 Посмотреть сообщение
С плюсами третий день работаю
тогда вам сначала ознакомится попрактиковаться с правилом Трех/Пяти
Вы так и не ответили на вопрос знакомы ли вы с этими правилами ?
0
6 / 6 / 1
Регистрация: 09.02.2016
Сообщений: 296
07.09.2024, 21:08  [ТС]
Добрался до компа.
Цитата Сообщение от Алексей1153 Посмотреть сообщение
assert(_outputs->size()==outputs->size());
Вылетает в Hardfault при выполнении этой строки. Рабатаю в CubeIDE, вот детали ошибки, больше не нашел:
HardFault_Handler() at stm32f4xx_it.c:85 0x8009a34
Цитата Сообщение от SmallEvil Посмотреть сообщение
а вы знаете про правило Трех/Пяти/Нуля ?
Изначально подумал, что какой-то стёб, но оказывается такое реально есть)
Прочел несколько статей, но пока как обычно - в теории понятно, но как применять на практике непонятно.

Цитата Сообщение от SmallEvil Посмотреть сообщение
Я надеюсь у вас всё в одном потоке выполняется ?
Поток один, программа на данный момент простейшая.

Цитата Сообщение от SmallEvil Посмотреть сообщение
И для практического использования, для всех не низкоуровневых классов откажитесь от сырых указателей.
Замените их умными указателями.
Не знаю насколько оправдано, но на данный момент стараюсь по возможности не использовать лишние навороты - пишу ВПО для микроконтроллера с частотой 96МГц. Переход с С на С++ и так ударил по его ресурсам, но на чистом С писать нервы уже не позволяют. Ищу компромиссы)

Цитата Сообщение от SmallEvil Посмотреть сообщение
После уничтожения объекта никто спецом не будет очищать ваши данные.
Это да, но тогда по логике если я скопировал указатель с тем же типом и который указывает на тот же участок памяти что и изначальный, то и операции долны быть допустимы аналогичные. А тут вон что - я в отладке могу вскрыть объект и посмотреть все внутренности, в коде тоже могу манипулировать свободно - ошибок нет, но приравнять указатели не получается.
На скриншоте отметил, что это момент, когда мы уже прошли момент приравнивания указателей, но у outputs и _outputs:
1) разные адреса (хотя тут может так и должно быть, пока не уверен);
2) разная структура объектов - у _outputs я могу увидеть внутренние классы с валидными значениями, а у outputs значений нет.

А теперь по коду сверху вниз:

Тут собственно создается вектор и сразу пробрасывается в метод инициализации другого класса:
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
    void UserMain::afterInit(){
        static const std::string curFuncName = "afterInit";
 
        try{
            //logger.log(curNamespaceName, curClassName, curFuncName, " started...");
 
            std::vector<IsxExtensionsCommon::PortPin> outputs3v3 {
                {.port = OUT_3V3_PP_1_GPIO_Port, .pin = OUT_3V3_PP_1_Pin},
                {.port = OUT_3V3_PP_2_GPIO_Port, .pin = OUT_3V3_PP_2_Pin},
                {.port = OUT_3V3_PP_3_GPIO_Port, .pin = OUT_3V3_PP_3_Pin},
                {.port = OUT_3V3_PP_4_GPIO_Port, .pin = OUT_3V3_PP_4_Pin},
                {.port = OUT_3V3_PP_5_GPIO_Port, .pin = OUT_3V3_PP_5_Pin},
                {.port = OUT_3V3_PP_6_GPIO_Port, .pin = OUT_3V3_PP_6_Pin},
                {.port = OUT_3V3_PP_7_GPIO_Port, .pin = OUT_3V3_PP_7_Pin},
            };
            std::vector<IsxExtensionsCommon::PortPin> outputsFt {
                {.port = OUT_FT_OD_1_GPIO_Port, .pin = OUT_FT_OD_1_Pin},
                {.port = OUT_FT_OD_2_GPIO_Port, .pin = OUT_FT_OD_2_Pin},
                {.port = OUT_FT_OD_3_GPIO_Port, .pin = OUT_FT_OD_3_Pin},
                {.port = OUT_FT_OD_4_GPIO_Port, .pin = OUT_FT_OD_4_Pin},
                {.port = OUT_FT_OD_5_GPIO_Port, .pin = OUT_FT_OD_5_Pin},
                {.port = OUT_FT_OD_6_GPIO_Port, .pin = OUT_FT_OD_6_Pin},
            };
            std::vector<IsxExtensionsCommon::PortPin> *ptrOutputs3v3 = &outputs3v3;
            std::vector<IsxExtensionsCommon::PortPin> *ptrOutputsFt = &outputsFt;
            hardware.initOutputs3v3(ptrOutputs3v3, GPIO_PIN_SET);
            hardware.initOutputsFt(ptrOutputsFt, GPIO_PIN_SET);
 
            //logger.log(curNamespaceName, curClassName, curFuncName, " successful finished!");
        }
Это класс, в котором объявлен вышеупомянутый метод (служит прокладкой для инициализации объектов внутреннего класса):
C++
1
2
3
4
5
6
namespace User::Hardwares{
 
    void Hardware::initOutputs3v3(std::vector<IsxExtensionsCommon::PortPin> *outputs, GPIO_PinState outputsOn){
        outputSignals3v3->init(outputs, outputsOn);
    }
....
А это уже метод, в котором и возникает проблема:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
        void OutputSignals::init(std::vector<IsxExtensionsCommon::PortPin> *outputs, GPIO_PinState outputsOn){
            //const std::string funcName = "init";
 
            _outputs = outputs;
 
            _outputsOn = outputsOn;
            _outputsOff = outputsOn == GPIO_PIN_SET ? GPIO_PIN_RESET : GPIO_PIN_SET;
 
            assert(_outputs->size()==outputs->size());
 
            int tmp1 = (int)outputs->size();
            int tmp2 = (int)_outputs->size();
        }
Миниатюры
Странное поведение указателя  
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13184 / 6820 / 1821
Регистрация: 18.10.2014
Сообщений: 17,263
07.09.2024, 21:41
Лучший ответ Сообщение было отмечено a13428711 как решение

Решение

Цитата Сообщение от a13428711 Посмотреть сообщение
А это уже метод, в котором и возникает проблема:
Скорее всего, вы что-то недоговариваете. Почему значения указателей отличаются?

Для начала надо бы сделать эти ваши проверки до того, как делается

C++
1
2
            _outputsOn = outputsOn;
            _outputsOff = outputsOn == GPIO_PIN_SET ? GPIO_PIN_RESET : GPIO_PIN_SET;
то есть сразу после присваивания указателей. Как там будет?

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

Также, почему поля _outputsOn и _outputsOff как будто содержат мусор? Чем равен указатель outputSignals3v3 в момент вызова

C++
1
2
3
void Hardware::initOutputs3v3(std::vector<IsxExtensionsCommon::PortPin> *outputs, GPIO_PinState outputsOn){
        outputSignals3v3->init(outputs, outputsOn);
    }
Объект вообще существует?
1
6 / 6 / 1
Регистрация: 09.02.2016
Сообщений: 296
07.09.2024, 22:25  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Для начала надо бы сделать эти ваши проверки до того, как делается
Тут обычное прирвнивание значений enum:
C++
1
2
    GPIO_PinState _outputsOn;
    GPIO_PinState _outputsOff;
где GPIO_PinState это enum. Но я проверил - перед ними картина та жею

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Также, почему поля _outputsOn и _outputsOff как будто содержат мусор?
А это тоже непонятно... На всякий случай объявление этих полей в хедере, мало ли что не так сделал:
C++
1
2
3
4
5
6
            std::vector<IsxExtensionsCommon::PortPin> *_outputs;
            GPIO_PinState _outputsOn;
            GPIO_PinState _outputsOff;
 
            void outputSetOn(IsxExtensionsCommon::PortPin &portPin);
            void outputSetOff(IsxExtensionsCommon::PortPin &portPin);
Щас гляну outputSignals3v3

Добавлено через 6 минут
Жесть какая, я бы в жизни не догадался, что если я обращусь к указателю, для которого не создавался объект, то он позволит мне через дебаггер провалится в метод в классе, на который должна указывать. Экземпляра же нет, как так-то?!

Ошибка была в том, что я случайно изменил объявление класса outputSignals3v3 с экземпляра на указатель:
C++
1
2
        OutputSignals* outputSignals3v3;
        OutputSignals* outputSignalsFt;
вместо:
C++
1
2
        OutputSignals outputSignals3v3;
        OutputSignals outputSignalsFt;
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Чем равен указатель outputSignals3v3 в момент вызова
Спасибо за наводку, мне бы в голову такое не пришло)
0
 Аватар для Azathtot
754 / 351 / 90
Регистрация: 07.01.2023
Сообщений: 1,451
08.09.2024, 19:02
Цитата Сообщение от a13428711 Посмотреть сообщение
Экземпляра же нет, как так-то?!
учитывая что VMT есть, а любой метод класса это функция вида f(class *this,.... то почему бы и нет? только this == nullptr будет
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13184 / 6820 / 1821
Регистрация: 18.10.2014
Сообщений: 17,263
08.09.2024, 20:08
Цитата Сообщение от Azathtot Посмотреть сообщение
учитывая что VMT есть,
???

Если бы там присутствовала VMT, то любой виртуальный вызов приводил бы к падению с 99.9% вероятностью.

Цитата Сообщение от Azathtot Посмотреть сообщение
а любой метод класса это функция вида f(class *this,.... то почему бы и нет?
Верно. Но все так просто только когда нет VMT, ибо с VMT нужно сначала добраться до метода.

Цитата Сообщение от Azathtot Посмотреть сообщение
только this == nullptr будет
Почему именно nullptr? Что передадите, то и будет. Возможно какой-то совсем посторонний мусор...
0
 Аватар для Azathtot
754 / 351 / 90
Регистрация: 07.01.2023
Сообщений: 1,451
08.09.2024, 20:29
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Почему именно nullptr?
Неверно написал this == UB правильнее конечно же. nullptr он будет только в дебаге.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
08.09.2024, 20:29
Помогаю со студенческими работами здесь

Странное поведение set::erase при изменении компаратора
Случайно столкнулся со странным поведением erase контейнера set. Вот такой код: int inverse = 0; struct cmp { bool...

Странное поведение, если имя локальной переменной лямбды совпадает с захваченной
Добрый день! В процессе решения одной задачи обратил внимание на странное поведение. Приведу упрощённый пример: #include...

Странное поведение указателя
Здравствуйте, наткнулся на непонятное мне поведение указателя или точнее менеджера памяти. Есть код: #include &lt;iostream&gt; #include...

Странное поведение указателя
#include &lt;iostream&gt; #include &lt;cstring&gt; int main(){ char line1=&quot;hello world!&quot;; char line2=&quot;hell word!&quot;; int...

Странное поведение указателя на массив внутри функции
Можете мне объяснить, почему некорректно выполняется функция, а точнее строка 52? #include&lt;stdio.h&gt; void crc16(unsigned...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: при выборе сотрудника (справочник Сотрудники) в ТЧ документа. . .
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
Система безопасности+живучести для сервера-слоя интернета (сети). Двойная привязка.
Hrethgir 08.04.2026
Далее были размышления о системе безопасности. Сообщения с наклонным текстом - мои. А как нам будет можно проверить, что ссылка наша, а не подделана хулиганами, которая выбросит на другую ветку и. . .
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru