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

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

Восстановить пароль Регистрация
 
hoggy
5427 / 2226 / 410
Регистрация: 15.11.2014
Сообщений: 5,016
Завершенные тесты: 1
18.03.2015, 22:03     Union, new placement, strict-aliasing, cross-platform #1
Доброго времени суток.

Ниже представленный код вроде бы работает.
Гонял его на компиляторах 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 это проконтролирует.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.03.2015, 22:03     Union, new placement, strict-aliasing, cross-platform
Посмотрите здесь:

C++ strict c++ : 64 bit int
Union C++
C++ platform sdk
Union C++
Windows Filtering Platform (WFP) C++ WinAPI
C++ Использование placement-new в перегруженном операторе присваивания
C++ Builder Озвучивание текста голосом через MS Speech Platform
[filesystem, cross-platform] посоветуйте библиотеку для работы с файловыми путями C++
C++ New placement
Placement new делигирование конструкторов C++
Cross referencing - проблема с include'ами C++
Cross referencing - проблема с include'ами C++

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

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Perfilov
264 / 165 / 43
Регистрация: 25.02.2015
Сообщений: 435
18.03.2015, 22:29     Union, new placement, strict-aliasing, cross-platform #2
полиморфный - это который унаследован от чего-то, у чего есть виртуальные функции?
из одних нулей - это когда байтблок взять и в нем одни нули? если так, то надо смотреть,
что в стандарте говорится на счет реализации виртуальности и RTTI. если метка внутри
объекта - то хотябы она не может быть нулевой а должна куда-то указывать (я о vptr).
если эту штуку как-то по другому хитро реализовали - то вроде бы в таком случае данные
объекта могут оказаться сплошными нулями.
ну и не совсем понял какое отношение это имеет к методу Empty
hoggy
5427 / 2226 / 410
Регистрация: 15.11.2014
Сообщений: 5,016
Завершенные тесты: 1
18.03.2015, 22:38  [ТС]     Union, new placement, strict-aliasing, cross-platform #3
Цитата Сообщение от Perfilov Посмотреть сообщение
полиморфный - это который унаследован от чего-то, у чего есть виртуальные функции?
Да. Содержит указатель на vtbl

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

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

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

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

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

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

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

Если же могут существовать такие объекты,
тогда данный механизм не сможет корректно распознать:
захватил ли он уже ресурс, или нет.
Perfilov
264 / 165 / 43
Регистрация: 25.02.2015
Сообщений: 435
19.03.2015, 00:09     Union, new placement, strict-aliasing, cross-platform #4
мысль понял. в общем тут закладка на то, что 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) - память покорраптится.
hoggy
5427 / 2226 / 410
Регистрация: 15.11.2014
Сообщений: 5,016
Завершенные тесты: 1
19.03.2015, 00:12  [ТС]     Union, new placement, strict-aliasing, cross-platform #5
Цитата Сообщение от Perfilov Посмотреть сообщение
я бы на это закладываться не стал.
понятно. спасибо.

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

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

Добавлено через 5 минут
хотя это хрень наверно. может вам еще добавить статик ассерт на предмет равенства sizeof(IResource) == sizeof(void*); если равны, то это вроде бы означает, что выравнивания нет.
Yandex
Объявления
19.03.2015, 00:36     Union, new placement, strict-aliasing, cross-platform
Ответ Создать тему
Опции темы

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