Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/6: Рейтинг темы: голосов - 6, средняя оценка - 4.67
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760

Union, new placement, strict-aliasing, cross-platform

18.03.2015, 22:03. Показов 1289. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток.

Ниже представленный код вроде бы работает.
Гонял его на компиляторах cl/mingw

http://rextester.com/OGKQ63240

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
//Title of this code
//g++  4.8.2
 
#include <iostream>
#include <cassert>
 
#include <type_traits>
 
 
struct IResource
{ 
    virtual void Foo()const =0; 
};
 
struct Resource: IResource
{ 
    virtual void Foo()const { std::cout<<"[ Resource ] hello\n"; }
};
 
 
union Holder
{
private:
    static void dimmy(){}
    typedef void (*unspecified)();
    
    char       mBuf[sizeof(IResource)];
    IResource* mHelper;
    
public:
    
    Holder():mHelper(nullptr){}
    
    IResource& Get()
    { 
        assert( mHelper && "ERROR: Holder is empty" );
        
        //промежуточная переменная служит для предотвращения угрозы
        //dereferencing type-punned pointer will break strict-aliasing rules
        IResource* obj = reinterpret_cast<IResource*>(mBuf);
        return *obj;
    }
    
    
    // true, если пуст
    bool Empty()const 
        { return mHelper? false: true; }
    
    // true, если пуст
    bool operator !()const 
        { return Empty(); }
   
    // true, если ресурс захвачен
    operator unspecified()const 
        { return !Empty()? dimmy: nullptr; }
    
 
    template<class T> void Capture()
    {
        static_assert( std::is_base_of<IResource, T>::value,
            "ERROR: T MUST BE THE HEIR OF THE CLASS 'IHelper'");
        
        static_assert( sizeof(T) == sizeof(IResource),
            "ERROR: SIZE OF T MUST BE == sizeof(IHelper)");
        
        new (mBuf) T;
    }
    
    void Clear() { mHelper = nullptr; }
    
    void View()const
    {
        std::cout << "addr = " << mHelper << mHelper << " : ";
        for(char i: mBuf)
            std::cout<<(int)i<<" ";
        std::cout<<'\n';
    }
};
 
int main()
{
    std::cout << "Hello, world!\n";
    
    Holder holder;
    holder.View();
    
    std::cout<<"holder is empty ? (must be true) : "
        << !holder<<'\n';
    
    holder.Capture<Resource>();
    holder.View();
    
    std::cout<<"holder is empty ? (must be false) : "
        << !holder<<'\n';
 
    std::cout<<"access to the resource:\n";
    holder.Get().Foo();
    
    std::cout<<"clear...\n";
    holder.Clear();
    
    std::cout<<"holder is empty ? (must be true) : "
        << !holder<<'\n';
    
}
Вопрос следующий: могу ли я закладываться на работоспособность метода
bool Holder::Empty()const ?

Другими словами, может ли теоретически так получится,
что валидный полиморфный объект окажется состоящим из одних нулей?


Кликните здесь для просмотра всего текста
Пожалуйста, не нужно обращать моё внимание на то,
что деструктор захваченного ресурса вызван не будет.
Так специально задумано.

Наследники не имеют права иметь собственных членов.
И static_assert это проконтролирует.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
18.03.2015, 22:03
Ответы с готовыми решениями:

Strict aliasing и memcpy
Что-то я никак не врублюсь, как согласуются между собой strict aliasing и функции жонглирующие void*? Возьмем для примера memcpy....

Каламбур типизации и strict aliasing
Есть ли какой-то стандартный способ обойти strict aliasing, с гарантией от UB? Конкретная задача: дан массив чисел. Требуется отсортировать...

Оптимизация кода, нарушающего правила strict aliasing
Доброго времени суток. Имеется такой код в ядре Linux: /* include/linux/netlink.h */ .... #define NETLINK_CB(skb) ...

5
265 / 165 / 56
Регистрация: 25.02.2015
Сообщений: 435
18.03.2015, 22:29
полиморфный - это который унаследован от чего-то, у чего есть виртуальные функции?
из одних нулей - это когда байтблок взять и в нем одни нули? если так, то надо смотреть,
что в стандарте говорится на счет реализации виртуальности и RTTI. если метка внутри
объекта - то хотябы она не может быть нулевой а должна куда-то указывать (я о vptr).
если эту штуку как-то по другому хитро реализовали - то вроде бы в таком случае данные
объекта могут оказаться сплошными нулями.
ну и не совсем понял какое отношение это имеет к методу Empty
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
18.03.2015, 22:38  [ТС]
Цитата Сообщение от Perfilov Посмотреть сообщение
полиморфный - это который унаследован от чего-то, у чего есть виртуальные функции?
Да. Содержит указатель на vtbl

Цитата Сообщение от Perfilov Посмотреть сообщение
из одних нулей - это когда байтблок взять и в нем одни нули?
Да. Критичны первые sizeof(void*) байт объекта.

Цитата Сообщение от Perfilov Посмотреть сообщение
то вроде бы в таком случае данные
объекта могут оказаться сплошными нулями.
Мне бы хотелось поконкретнее: может такое быть, или нет.

Цитата Сообщение от Perfilov Посмотреть сообщение
ну и не совсем понял какое отношение это имеет к методу Empty
Суть механизма в том, что это union,
у которого размер хранилища ресурсов совпадет с sizeof(void*)
Может быть больше, но не меньше.

В методе Clear:
C++
1
void Clear() { mHelper = nullptr; }
Происходит обнуление первых sizeof(void*) байт.

Как узнать, держит ли холдер ресурс или нет?
Можно глянуть: нулевой ли указатель в юнионе, или нет.

Если нулевой - значит первые sizeof(void*) байт были затерты.
Значит, холдер не содержит ресурс.

Это будет работать только если теоретически не может быть объектов,
у которых первые sizeof(void*) байт содержат нули.

Если же могут существовать такие объекты,
тогда данный механизм не сможет корректно распознать:
захватил ли он уже ресурс, или нет.
0
265 / 165 / 56
Регистрация: 25.02.2015
Сообщений: 435
19.03.2015, 00:09
мысль понял. в общем тут закладка на то, что vptr в начале. я бы на это закладываться не стал.
потом еще такой глюк:
буффер под объекты размера интерфейса:
char mBuf[sizeof(IResource)];

а захват такой:
C++
1
2
3
4
template<class T> void Capture()
{
  new (mBuf) T;
}
в вашем случае T == Resource , который без данных и поэтому sizeof(IResource) == sizeof(Resource).
как только sizeof(T) > sizeof(IResource) - память покорраптится.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
19.03.2015, 00:12  [ТС]
Цитата Сообщение от Perfilov Посмотреть сообщение
я бы на это закладываться не стал.
понятно. спасибо.

Цитата Сообщение от Perfilov Посмотреть сообщение
в вашем случае T == Resource , который без данных и поэтому sizeof(IResource) == sizeof(Resource).
как только sizeof(T) > sizeof(IResource) - память покорраптится.
ещё там стоит статический ассерт, который за этим следит.
так что никаких глюков.
0
265 / 165 / 56
Регистрация: 25.02.2015
Сообщений: 435
19.03.2015, 00:36
да, точно. на ассерты не обратил внимания.
выходит эта штука работает только с объектами без данных.
и в случае, когда все RTTI дела решаются за счет внедрения vptr в объект, он будет единственным.
что там с выравниваниями в этом случае - я тоже не знаю. здравый смысл подсказывает что не должно
быть сюрпризов и ничего лишнего для выравнивания впихнуто не будет. но черт его знает что будет на самом
деле. может там косяки пойдут из-за расположения объекта Holder или какая-нибудь экзотика встретится.
в общем все хитро и изначальный вопрос остается открытым

Добавлено через 12 минут
как вам вариант использовать не nullptr для проверки, а адрес какой-нибудь константы или статической переменной? он ведь должен быть уникальным. врятли какой-нибудь vptr будет на нее указывать.

Добавлено через 5 минут
хотя это хрень наверно. может вам еще добавить статик ассерт на предмет равенства sizeof(IResource) == sizeof(void*); если равны, то это вроде бы означает, что выравнивания нет.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
19.03.2015, 00:36
Помогаю со студенческими работами здесь

warning: dereferencing pointer 't' does break strict-aliasing rules
Здравствуйте, уважаемые специалисты! К чему может привести данное предупреждение? Что нужно сделать, чтобы его не было? typedef...

Cross-platform
Приветствую! Ребята подскажите, если способ писать приложение для windows, Linux, Mac на подобие Xamarin-а?

LambdaNative: Cross-Platform Scheme
LambdaNative: Cross-Platform Scheme Applications LambdaNative allows you to create native applications on iOS, Android, Blackberry, OS...

Разработка cross platform приложения
Добрый день Знающие люди подскажите пожалуйста Есть необходимость разработать проект для App Store и Play Market. Xamarin...

Release .apk (Cross-platform)
Всем привет! Столкнулся с такой проблемой. При debug под Android на физическом устройстве (version 5.0) приложение запускается и работает...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
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