Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.86/7: Рейтинг темы: голосов - 7, средняя оценка - 4.86
199 / 155 / 45
Регистрация: 11.11.2019
Сообщений: 348

Уточнение работы теста для контейнера list стандартной библиотеки

16.03.2020, 01:59. Показов 1499. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток уважаемые форумчане. Прошу помочь мне ответить на интересующий меня вопрос. Для начала входная информация. Ниже представлен код теста под названием "Dev08_576265_list_remove" из пакета исходников стандартной библиотеки в реализации Майкрософт.
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
#include <assert.h>
#include <list>
 
struct Val {
    int value;
    unsigned int canary;
    Val() : value(0), canary(0xDEADBEEF) {}
    Val(int val) : value(val), canary(0x600DF00D) {}
    ~Val() {
        canary = 0xDEADBEEF;
    }
};
 
bool operator==(const Val& val1, const Val& val2) {
    assert(val1.canary == 0x600DF00D && val2.canary == 0x600DF00D);
    return val1.value == val2.value;
}
 
int main() {    
    // When passed a reference to an element of the list, std::list::remove
    // will defer destruction of that element's node until it returns.
    std::list<Val> l;
 
    l.push_back(Val(1));
    l.push_back(Val(2));
    l.remove(l.front());
}
Из короткого пояснения можно понять, что тест предназначен для проверки правильности функционирования "отложенного" удаления узла списка, если в качестве параметра в метод remove() передана ссылка на узел, содержащийся в этом же самом списке.
На всякий случай приведу код метода remove():
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void remove(const _Ty& _Val)
{   // erase each element matching _Val
    iterator _Val_it = end();
 
    for (iterator _First = begin(); _First != end(); )
        if (*_First == _Val)
            if (_STD addressof(*_First) == _STD addressof(_Val))
                _Val_it = _First++;
            else
                _First = erase(_First);
        else
            ++_First;
 
    if (_Val_it != end())
        erase(_Val_it);
}
Как видим, "отложенное" удаление действительно присутствует.
Теперь собственно вопрос. Что ожидали получить разработчики в случае неудачного завершения теста? Единственный видимый вариант - это вылет ассерта в перегруженном операторе. Но по какой причине должен вылететь этот ассерт?
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
16.03.2020, 01:59
Ответы с готовыми решениями:

На базе контейнера vector из стандартной библиотеки С++ создайте шаблон класса Set,
На базе контейнера vector из стандартной библиотеки С++ создайте шаблон класса Set, в котором каждый объект может храниться только в одной...

Изучение функция стандартной библиотеки для новичка
Здравствуйте! Поделитесь опытом: каким образом надо изучать функции стандартных библиотек С++. Может, надо читать какие-либо книги (книги,...

Линковка стандартной библиотеки для релиза на чужие компы
Есть ли разница как линковать стандартную библиотеку - статически или динамически? Компилятор mingw64. В моем приложении использую...

9
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
16.03.2020, 04:52
Цитата Сообщение от fao Посмотреть сообщение
Но по какой причине должен вылететь этот ассерт?
Там же хорошо видно, что при удалении элемента в его память (на месте поля canary) деструктор записывает значение 0xDEADBEEF. Если кто-то по ошибке попробует работать с памятью удаленного элемента, как с "живым" элементом, он будет видеть 0xDEADBEEF в поле canary.

У "живых" элементов поле canary хранится 0x600DF00D. Если по какой-то причине "убитый" элемент попадет в оператор ==, сработает assert.
0
199 / 155 / 45
Регистрация: 11.11.2019
Сообщений: 348
16.03.2020, 04:59  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если по какой-то причине "убитый" элемент попадет в оператор ==, сработает assert.
ну то есть внутри assert идет обращение к полю удаленного объекта. Но ведь это UB. Где гарантия, что assert правильно сработает?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
16.03.2020, 05:05
Цитата Сообщение от fao Посмотреть сообщение
ну то есть внутри assert идет обращение к полю удаленного объекта. Но ведь это UB. Где гарантия, что assert правильно сработает?
Ну так цель данного теста как раз и состоит в том, чтобы отловить UB, когда UB уже фактически произошло. Ясно, что не выходя за рамки стандартного языка С++ постфактум отловить UB невозможно. Это всегда делается платформено-зависимыми средствами, т.е. "хаками". Работоспособность такой техники зависит от реализации. Данный тест - это именно "хак", написанный именно для майкрософтовской реализации. Хотя он может работать и в других реализациях.
1
199 / 155 / 45
Регистрация: 11.11.2019
Сообщений: 348
16.03.2020, 05:39  [ТС]
Вот это меня смущает. По идее тест должен быть надежным. А тут получается, что объект был удален. Мы внутри assert обращаемся к его полю canary, которое в деструкторе приобрело значение 0xDEADBEEF. Но память-то уже свободна. Кто мешает к моменту проверки внутри assert в это самое место положить 0x600DF00D (пусть вероятность мала, но все же).

Добавлено через 19 минут
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
"хак", написанный именно для майкрософтовской реализации
то есть парни из Майкрософт в данном случае на 100% уверены, что никто и ничто не изменит значение в освобожденной ячейке памяти вплоть до ее проверки. Ок. Спасибо.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
16.03.2020, 07:11
Цитата Сообщение от fao Посмотреть сообщение
Вот это меня смущает. По идее тест должен быть надежным. А тут получается, что объект был удален. Мы внутри assert обращаемся к его полю canary, которое в деструкторе приобрело значение 0xDEADBEEF. Но память-то уже свободна. Кто мешает к моменту проверки внутри assert в это самое место положить 0x600DF00D (пусть вероятность мала, но все же).
Этот тест абсолютно надежен. Речь идет об однопоточном приложении, причем перед вами - тестовая программа целиком. Где вы в ней видите кого-то, кто мог бы изменить это значение в памяти?

Память может либо освободиться "по настоящему", т.е. вернуться ОС, в каковом включатся механизмы предотвращения доступа к освобожденной памяти уровня ОС и при ошибочном доступе программа просто упадет. Либо память останется во владении приложения, в каком при ошибочном доступе случае сработает данный трюк с канарейкой. И так и так авторы теста достигают желаемого эффекта.

Цитата Сообщение от fao Посмотреть сообщение
то есть парни из Майкрософт в данном случае на 100% уверены, что никто и ничто не изменит значение в освобожденной ячейке памяти вплоть до ее проверки.
И вполне справедливо уверены.

Именно такими методами испокон веков и реализовались механизмы санитизации доступа к памяти. Все так делают. Именно так это и делается.
0
199 / 155 / 45
Регистрация: 11.11.2019
Сообщений: 348
16.03.2020, 14:14  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Именно такими методами испокон веков и реализовались механизмы санитизации доступа к памяти.
Ок, я сейчас как раз занимаюсь вопросами организации тестирования компонентов и просматриваю кто и как это делает. Меня немного удивил данный подход, тем более что с тем же успехом этот тест можно было написать и без "хаков".
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
16.03.2020, 18:27
Лучший ответ Сообщение было отмечено DrOffset как решение

Решение

Цитата Сообщение от fao Посмотреть сообщение
Меня немного удивил данный подход, тем более что с тем же успехом этот тест можно было написать и без "хаков".
Это как же? И, главное, зачем?

Как я уже говорил выше, подход совершенно не удивительный, а общеизвестный и широко используемый повсеместно. Организация no-mans-land ("контрольно-следовых полос") областей в коде вокруг объектов, заполнение освобожденных блоков памяти "посторонним" значением, и даже "ненужное" обнуление указателей в деструкторах объектов - это все вариации этого же самого подхода. Это настолько просто, удобно, эффективно и универсально, что непонятно, зачем придумывать что-то еще ("без хаков").

P.S. И, еще раз, "хаки" тут есть только с точки зрения внешнего "пользователя" языка С++, который подчиняется требованиям стандарта языка. Но этот код - это код уровня реализации стандартной библиотеки. Это формально вообще не С++, а некий платформенно-зависимый псевдоязык, на котором написана стандартная библиотека. В рамках этого языка никакого "хака" тут нет.
1
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,518
16.03.2020, 19:45
Цитата Сообщение от fao Посмотреть сообщение
Но ведь это UB. Где гарантия, что assert правильно сработает?
Вы для чего вообще тесты пишите? ))

Гарантии работоспособности предоставляют тесты.
В тестировании есть такое понятие: "презумпция невиновности"
Суть: функция foo доверяет функции bar, при условии, что все тесты bar зеленые.

Что бы получить гарантии правильного срабатывния assert, нужно два теста:
1) Тест, где мы точно знаем, что assert должен сработать
2) Тест, где мы точно знаем, что assert не должен сработать.

Если оба теста зеленые, значит всё хорошо.




Пример:
Функция strlen принимает указатель на строку, и возвращает длину этой строки.
Если на вход подать невалидный аргумент, тогда должен сработать ассерт.

C++
1
2
3
4
5
6
7
8
9
10
TEST(strlen, checkAssert_1)
{
    const chat* null = nullptr;
    ASSERT_DEATH(strlen(null));
}
TEST(strlen, checkAssert_2)
{
    const chat* text = "";
    ASSERT_TRUE(strlen(text) == 0);
}

Формально, с точки зрения языка с++, в некотором коде может присутствовать UB.
Но что такое UB с точки зрения языка?
Некоторые почему-то думают, что раз UB, то теперь может случиться всё, что угодно.
Ничего подобного.
"Неопределенное поведение" - это просто ситуация, для которой стандарт не предусматривает никаких гарантий.

Однако, любое поведение в конечном счете зависит от конкретной реализации на конкретной платформе.
И для этой конкретной реализации факт наличия UB уже ничего не меняет.
Поведение на этой конкретной платформе не может внезапно измениться по волшебству.

Пока оба теста зеленые, можно считать что на этой конкретной платформе ассерт работает как нужно.
и до тех пор, пока явным образом не будет доказано обратное, для ассерта действует презумпция невиновности.
0
199 / 155 / 45
Регистрация: 11.11.2019
Сообщений: 348
16.03.2020, 20:28  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
И, главное, зачем?
Просто намерен детально изучить данный вопрос, но при этом хочу расширить фарватер познания. Поэтому рассматриваю разные варианты. За подсказку спасибо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
16.03.2020, 20:28
Помогаю со студенческими работами здесь

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

Функции стандартной библиотеки для отображения одной системы счисления в другую
Вопрос заключается в том, существует ли в стандартной библиотеки функции типа atoi(), но для 2-8-16 ричной системы? И наоборот, которые...

Какой препроцессор используется для подключения стандартной библиотеки ввода-вывода?
Какой препроцессор используется для подключения стандартной библиотеки ввода-вывода? 1) include 2) iostream 3) define 4) io.sys

Подскажите пожалуйста как использовать __gnu_parallel::for_each для контейнера <list>
Добрый день! Я использую си++ 17. В STL есть встроенные возможности параллельного программирования. У меня возник вопрос... Подскажите...

Какие библиотеки нужны для работы с видео avi, flv и для работы с mp3?
Hello world! Подскажите пожалуйста какие библиотеки нужни мне для работи с видео .avi, flv и т.д и для работи .mp3? Союираюс...


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru