Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Это мелочи, на это есть GetProcAddress
E>А звать как? Например операторы?
Шут его знает. Как-нибудь сформировать указатель на метод-член класса, по нему и вызвать. В крайнем случае через asm.
E>Я бы, лучше, при помощи DEF файла экспортировал из DLL методы сразу под несколькими именами...
Что-то я плохо понимаю. А в EXE как вызывать будем ? С чего это компилятор для, скажем
A* pa = ...; pa->myfunc();
будет какое-то иное имя, кроме того, что он наманглил, использовать ?
With best regards
Pavel Dvorkin
Re[4]: Представление класса в памяти разными компиляторами
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>>Это мелочи, на это есть GetProcAddress E>>А звать как? Например операторы? PD>Шут его знает. Как-нибудь сформировать указатель на метод-член класса, по нему и вызвать. В крайнем случае через asm.
О! Это должно быть дико удобно
E>>Я бы, лучше, при помощи DEF файла экспортировал из DLL методы сразу под несколькими именами... PD>Что-то я плохо понимаю. А в EXE как вызывать будем ? С чего это компилятор для, скажем
PD>A* pa = ...; pa->>myfunc();
PD>будет какое-то иное имя, кроме того, что он наманглил, использовать ?
Он его и будет. В зависимости от того, какой компилятор компилил EXE будет звать разное имя. Соответственно мы можем экспортировать нужный метод под всеми нужными именами. А под некоторыми можно даже адаптеры экспортировать, на случай, если нет совсем никакого способа объявить класс так, чтобы быть совместимым с каким-то конкретным компилятором, можно ему подсунуть адаптеры...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Представление класса в памяти разными компиляторами
Здравствуйте, fanruten, Вы писали:
F>Допустим есть класс экземпляр которого возвращает функция реализованная в dll.
F>Какие гарантии ,что при использование этой dll в коде собранном при помощи компилятора Б, вызов функций членов Foo будет правильный? F>Ведь как я понимаю различные компиляторы могут по разному представлять экземпляр класса.
Функции-члены классов нельзя вызывать через границу DLL.
К членам-данным не-POD-классов нельзя обращаться через границу DLL.
Экземпляры классов нельзя удалять посредством delete через границу DLL.
Единственное, что можно делать — это передавать туда-сюда указатели на экземпляры. При условии, что вся работа с экземпляром остаётся по одну сторону границы DLL, а по другую стророну это просто обезличенный указатель на чёрный ящик.
COM-объекты можно использовать через границу DLL, при условии, что компиляторы по обе стороны поддерживают COM и все конструкции, употреблённые в описании интерфейса.
Re[2]: Представление класса в памяти разными компиляторами
Здравствуйте, Centaur, Вы писали:
C>Функции-члены классов нельзя вызывать через границу DLL. C>К членам-данным не-POD-классов нельзя обращаться через границу DLL.
При некоторой ловкости и для известных заранее пар компиляторов можно, тем не менее, но с приложением определённых усилий со стороны DLL, например.
C>Экземпляры классов нельзя удалять посредством delete через границу DLL.
Это да.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Представление класса в памяти разными компиляторами
Здравствуйте, Centaur, Вы писали:
C>Здравствуйте, fanruten, Вы писали:
F>>Допустим есть класс экземпляр которого возвращает функция реализованная в dll.
F>>Какие гарантии ,что при использование этой dll в коде собранном при помощи компилятора Б, вызов функций членов Foo будет правильный? F>>Ведь как я понимаю различные компиляторы могут по разному представлять экземпляр класса.
C>Функции-члены классов нельзя вызывать через границу DLL. C>К членам-данным не-POD-классов нельзя обращаться через границу DLL. C>Экземпляры классов нельзя удалять посредством delete через границу DLL.
C>Единственное, что можно делать — это передавать туда-сюда указатели на экземпляры. При условии, что вся работа с экземпляром остаётся по одну сторону границы DLL, а по другую стророну это просто обезличенный указатель на чёрный ящик.
C>COM-объекты можно использовать через границу DLL, при условии, что компиляторы по обе стороны поддерживают COM и все конструкции, употреблённые в описании интерфейса.
Еще. Классы, в которых есть non-POD типы, должны создаваться/удаляться там, где находится код функций, которые работают с этими классами. Иначе можно нарваться на различное вычисление размера структур и соотв. выделение неправильного объема памяти.
Re[3]: Представление класса в памяти разными компиляторами
Здравствуйте, Vain, Вы писали:
C>>>Экземпляры классов нельзя удалять посредством delete через границу DLL. E>>Это да. V>Это почему?
В том числе, имеется в виду, "через границу CRT DLL"
Нужно обеспечивать сочетаемость пар operator new-delete и конструктор-деструктор.
"Находятся в одном модуле" — более сильное условие, чем "сочетаемы друг с другом".
Но зато оно более просто проверяемое; не надо задумываться о зависимостях и совместимостях.
Скажем, если инлайновый деструктор обращается к каким-то инлайновым же статическим переменным (классика жанра: std::map) — нехорошо выйдет. А пойди проверь — куда ведут все эти инлайны...
Проще убедиться, что объект удаляется там, где создан, и всё.
Перекуём баги на фичи!
Re[5]: Представление класса в памяти разными компиляторами
Здравствуйте, Кодт, Вы писали:
C>>>>Экземпляры классов нельзя удалять посредством delete через границу DLL. E>>>Это да. V>>Это почему? К>В том числе, имеется в виду, "через границу CRT DLL" К>Нужно обеспечивать сочетаемость пар operator new-delete и конструктор-деструктор.
И не только это.
К>"Находятся в одном модуле" — более сильное условие, чем "сочетаемы друг с другом". К>Но зато оно более просто проверяемое; не надо задумываться о зависимостях и совместимостях. К>Скажем, если инлайновый деструктор обращается к каким-то инлайновым же статическим переменным (классика жанра: std::map) — нехорошо выйдет.
А какие там статические переменные?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[6]: Представление класса в памяти разными компиляторами
Здравствуйте, Vain, Вы писали:
К>>Скажем, если инлайновый деструктор обращается к каким-то инлайновым же статическим переменным (классика жанра: std::map) — нехорошо выйдет. V>А какие там статические переменные?
За все на свете реализации не поручусь, а в динкумваровской (вижуаловской) — были.
Как известно, мап сделан на КЧД с фиктивными листьями. Так вот, эти листья можно воплотить 4 способами
— трактовать нулевые указатели как указатели на фиктивные листья — это приводит к ветвлениям и просадке производительности
— создать честные листья на куче — затраты памяти
— паттерн "нулевой объект"
— — экземпляр фиктивного листа прямо в теле мапа — затраты памяти (увеличение размера мапа); дорогая процедура обмена/присваивания мапов друг с другом (нужно корректировать всё дерево, чтобы гарантировать время жизни листьям)
— — экземпляр фиктивного листа в глобальной переменной
— — можно и пятый способ: разделяемое владение немногими неразличимыми между собой листьями... но это — опять просадка скорости и излишнее усложнение
Перекуём баги на фичи!
Re[7]: Представление класса в памяти разными компиляторами
Здравствуйте, Кодт, Вы писали:
К>>>Скажем, если инлайновый деструктор обращается к каким-то инлайновым же статическим переменным (классика жанра: std::map) — нехорошо выйдет. V>>А какие там статические переменные?
К>За все на свете реализации не поручусь, а в динкумваровской (вижуаловской) — были. К>Как известно, мап сделан на КЧД с фиктивными листьями. Так вот, эти листья можно воплотить 4 способами К>- трактовать нулевые указатели как указатели на фиктивные листья — это приводит к ветвлениям и просадке производительности К>- создать честные листья на куче — затраты памяти К>- паттерн "нулевой объект" К>- — экземпляр фиктивного листа прямо в теле мапа — затраты памяти (увеличение размера мапа); дорогая процедура обмена/присваивания мапов друг с другом (нужно корректировать всё дерево, чтобы гарантировать время жизни листьям) К>- — экземпляр фиктивного листа в глобальной переменной К>- — можно и пятый способ: разделяемое владение немногими неразличимыми между собой листьями... но это — опять просадка скорости и излишнее усложнение
А почему бы просто в корне не хранить? Или я что-то недопонял?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[8]: Представление класса в памяти разными компиляторами
Здравствуйте, Vain, Вы писали:
V>А почему бы просто в корне не хранить? Или я что-то недопонял?
В любом случае, это будет оверхед — по сравнению со статическим расшаренным объектом.
На самом деле, суть бага в том, что признак "это фиктивный лист" выводился не из того, что "это лист", а "адрес этого объекта равен адресу нашего синглетона". Эта проверка более дешёвая, но не выдерживает испытания многомодульностью (и нарушением ODR, на самом деле: ибо, у нас появляются несколько экземпляров статической переменной).
Перекуём баги на фичи!
Re[9]: Представление класса в памяти разными компиляторами
Здравствуйте, Кодт, Вы писали:
V>>А почему бы просто в корне не хранить? Или я что-то недопонял? К>В любом случае, это будет оверхед — по сравнению со статическим расшаренным объектом. К>На самом деле, суть бага в том, что признак "это фиктивный лист" выводился не из того, что "это лист", а "адрес этого объекта равен адресу нашего синглетона". Эта проверка более дешёвая, но не выдерживает испытания многомодульностью (и нарушением ODR, на самом деле: ибо, у нас появляются несколько экземпляров статической переменной).
Как я понимаю, дерево в реализации STL это технически тот же самый лист (т.к. STL требует линейной итерируемости от любого контейнера), т.е. ноды не перемещаемы в памяти, а т.к. минимум корень всегда будет существовать при хотябы одном листе, то это и есть нормальное решение. А неявные статические переменные в контейнерах и указатели на тело объекта в нодах это — от лукавого.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: Представление класса в памяти разными компиляторами
Здравствуйте, c-smile, Вы писали:
CS>Можно проверить поддерживает ли данный компилятор COM или нечто аналогичное. CS>Если "да" то в принципе можно делать предположения об однообразии. А лучше прямо COM интерфейсы и писать.
Насколько я могу припомнить, в COM нигде структурами данных не обмениваются. COM полагается только на способ размещения vptr и способ организации vtbl.
Re[10]: Представление класса в памяти разными компиляторами
Здравствуйте, Vain, Вы писали:
V>Как я понимаю, дерево в реализации STL это технически тот же самый лист (т.к. STL требует линейной итерируемости от любого контейнера), т.е. ноды не перемещаемы в памяти, а т.к. минимум корень всегда будет существовать при хотябы одном листе, то это и есть нормальное решение. А неявные статические переменные в контейнерах и указатели на тело объекта в нодах это — от лукавого.
Технически это всё-таки дерево. Полный обход дерева — за O(n), а одна итерация занимает переменное время.
Фиктивный корень, подобно фиктивным концам списка, у дерева тоже есть и является принадлежностью конкретного контейнера. Это end().
А фиктивные листья несут два признака: цвет:чёрный и лист:да.
Сейчас посмотрел на реализацию в VC8, там фиктивные листья совпадают с фиктивным корнем. Который тоже чёрный и пустой.
То есть, граф такого дерева выглядит вот так