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

C++

Войти
Регистрация
Восстановить пароль
 
hoggy
6719 / 2904 / 499
Регистрация: 15.11.2014
Сообщений: 6,538
Завершенные тесты: 1
#1

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

18.03.2015, 22:03. Просмотров 394. Ответов 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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.03.2015, 22:03
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Union, new placement, strict-aliasing, cross-platform (C++):

[filesystem, cross-platform] посоветуйте библиотеку для работы с файловыми путями - C++
Добрый день. нужно что-то цивилизованное, что отвечает требованиям: 1. (важно) что бы можно было собирать целевой продукт...

Использование placement-new в перегруженном операторе присваивания - C++
Всем хей. Допустим, у меня определён конструктор копирования для класса T. Теперь я хочу перегрузить для T оператор присваивания и,...

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

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

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

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

5
Perfilov
264 / 164 / 43
Регистрация: 25.02.2015
Сообщений: 435
18.03.2015, 22:29 #2
полиморфный - это который унаследован от чего-то, у чего есть виртуальные функции?
из одних нулей - это когда байтблок взять и в нем одни нули? если так, то надо смотреть,
что в стандарте говорится на счет реализации виртуальности и RTTI. если метка внутри
объекта - то хотябы она не может быть нулевой а должна куда-то указывать (я о vptr).
если эту штуку как-то по другому хитро реализовали - то вроде бы в таком случае данные
объекта могут оказаться сплошными нулями.
ну и не совсем понял какое отношение это имеет к методу Empty
0
hoggy
6719 / 2904 / 499
Регистрация: 15.11.2014
Сообщений: 6,538
Завершенные тесты: 1
18.03.2015, 22:38  [ТС] #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*) байт содержат нули.

Если же могут существовать такие объекты,
тогда данный механизм не сможет корректно распознать:
захватил ли он уже ресурс, или нет.
0
Perfilov
264 / 164 / 43
Регистрация: 25.02.2015
Сообщений: 435
19.03.2015, 00:09 #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) - память покорраптится.
0
hoggy
6719 / 2904 / 499
Регистрация: 15.11.2014
Сообщений: 6,538
Завершенные тесты: 1
19.03.2015, 00:12  [ТС] #5
Цитата Сообщение от Perfilov Посмотреть сообщение
я бы на это закладываться не стал.
понятно. спасибо.

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

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

Добавлено через 5 минут
хотя это хрень наверно. может вам еще добавить статик ассерт на предмет равенства sizeof(IResource) == sizeof(void*); если равны, то это вроде бы означает, что выравнивания нет.
0
19.03.2015, 00:36
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.03.2015, 00:36
Привет! Вот еще темы с ответами:

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

Cross-platform development environment written in Scheme - Lisp
LambdaNative is an open-source (BSD licensed) cross-platform development environment written in Scheme (Gambit-C), supporting Android, iOS,...

union как определить из какой таблице запись после UNION? - MySQL
Подскажите пожалуйста! Вот например две таблице (TEBLE_1) у которой поля row_1(BIGINT) и (TABLE_2) у которой поля row_2(TEXT) Я ИХ...

New placement - C++
Что это за юмор такой? #include &lt;iostream&gt; #include &lt;new&gt; using namespace std; int main() { double *a= new...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

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