Классы без CRT

Тема в разделе "LANGS.C", создана пользователем Y_Mur, 30 мар 2009.

  1. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    При отключении стандартных библиотек классы в пределах текущей функции (testClass_1::aa в примере ниже) нормально создаются и уничтожаются. С new, delete сложнее – они определены в CRT и непонятно как различать случаи простых переменных и массивов от объектов, требующих вызова конструктора.
    Но в MSVC 9 оператор new из CRT не использует этого механизма, и собственно даже если бы использовал, всё равно непонятно как вызвать конструктор для «пока несуществующего» класса и передать ему this.
    Гугл выдал ряд аналогичных вопросов на других форумах так и оставшихся без ответов и единственный более менее внятный пример.
    Остановился на варианте:
    Код (Text):
    1. #include <windows.h>
    2. #pragma comment(linker,"/ENTRY:main")
    3.  
    4. //===============================================
    5. UINT const CF_CREATE_NEW = 0x00000001;
    6. //===============================================
    7. class testClass_1
    8. {   UINT flags;
    9.     int a;
    10.     int b;
    11. public:
    12.     testClass_1(UINT flags = 0);
    13.     ~testClass_1();
    14.     int get_a(void) { return a; };
    15.     int get_b(void) { return b; };
    16. };
    17. //-------------------------------------------------------
    18. testClass_1::testClass_1(UINT flags)
    19. {
    20.     this->flags = flags;
    21.     this->a = 0x5;
    22.     this->b = 0x7;
    23. };
    24. //-------------------------------------------------------
    25. testClass_1::~testClass_1()
    26. {
    27.     if (this->flags & CF_CREATE_NEW)
    28.         HeapFree(activeHeap, 0, this);
    29. };
    30.  
    31. //======================================================================================
    32. //  Глобальные переменные
    33. LPVOID activeHeap;
    34. //======================================================================================
    35. //  Функция входа в программу
    36. int main(void)
    37. {
    38.     activeHeap = GetProcessHeap();
    39.  
    40.     // Объект в пределах функции (флаг не нужен)
    41.     testClass_1  aa;
    42.    
    43.     // заменитель new (указано через флаг вручную)
    44.     testClass_1 *bb;
    45.     bb = (testClass_1 *)HeapAlloc(activeHeap, 0, sizeof testClass_1);
    46.     bb->testClass_1::testClass_1(CF_CREATE_NEW);
    47.  
    48.     char outStr[1024];
    49.     wsprintf((LPSTR)&outStr, "aa.a = 0x%x, bb.b = 0x%x\nразмер класса = %d", aa.get_a(), bb->get_b(), sizeof testClass_1);
    50.     MessageBox(NULL, (LPSTR)&outStr, "Мой тест классов", MB_OK);
    51.  
    52.     // заменитель delete
    53.     bb->testClass_1::~testClass_1();
    54.  
    55.     return 0;
    56. }
    где различать способ создания объекта в конструкторе приходится по флагу задаваемому вручную.
    Совсем без флага не получается определить необходимость HeapFree в деструкторе.
    Есть ли более изящное решение?
     
  2. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    а почему бы не задать свои new и delete?
     
  3. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    GoldFinch
    Хотя мысль хорошая - действительно лучше сделать раздельные new_v, new_c, delete_v, delete_c соответственно для переменных и классов и скрыть вызов Heap и конструктора ;)
     
  4. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Код (Text):
    1. #include <windows.h>
    2. #pragma comment(linker,"/ENTRY:main")
    3.  
    4. //===============================================
    5. UINT const CF_CREATE_NEW = 0x00000001;
    6. //===============================================
    7. //  Глобальные переменные
    8. LPVOID activeHeap;
    9.  
    10.  
    11. class testClass_1 {
    12.     int id;
    13.     int a;
    14.     int b;
    15. public:
    16.     testClass_1(int _id);
    17.     ~testClass_1();
    18.     int get_a(void) { return a; };
    19.     int get_b(void) { return b; };
    20. };
    21. //-------------------------------------------------------
    22. testClass_1::testClass_1(int _id) {
    23.     id = _id;
    24.     this->a = 0x5;
    25.     this->b = 0x7;
    26.     char outStr[1024];
    27.     wsprintf((LPSTR)&outStr, "id = 0x%x", id);
    28.     MessageBox(NULL, (LPSTR)&outStr, "Constructor", MB_OK);
    29. };
    30. //-------------------------------------------------------
    31. testClass_1::~testClass_1() {
    32.     char outStr[1024];
    33.     wsprintf((LPSTR)&outStr, "id = 0x%x", id);
    34.     MessageBox(NULL, (LPSTR)&outStr, "Destructor", MB_OK);
    35. };
    36.  
    37. //======================================================================================
    38.  
    39. inline void* operator new(size_t cb) {
    40.     return (void*)HeapAlloc(activeHeap, 0, cb);
    41. };
    42.  
    43. inline void operator delete(void* ptr) {
    44.     HeapFree(activeHeap, 0, ptr);
    45. };
    46.  
    47.  
    48.  
    49. //  Функция входа в программу
    50. int main(void) {
    51.     activeHeap = GetProcessHeap();
    52.  
    53.     // Объект в пределах функции (флаг не нужен)
    54.     testClass_1  aa(0xAA);
    55.    
    56.     // заменитель new (указано через флаг вручную)
    57.     testClass_1* bb = new testClass_1(0xBB);
    58.  
    59.     char outStr[1024];
    60.     wsprintf((LPSTR)&outStr, "aa.a = 0x%x, bb.b = 0x%x\nразмер класса = %d", aa.get_a(), bb->get_b(), sizeof testClass_1);
    61.     MessageBox(NULL, (LPSTR)&outStr, "Мой тест классов", MB_OK);
    62.  
    63.     // заменитель delete
    64.     delete bb;
    65.  
    66.     return 0;
    67. }
    почему не так?

    *добавил msgbox в конструктор и деструктор
     
  5. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    или так
    Код (Text):
    1. class testClass_1 {
    2.     int id;
    3.     int a;
    4.     int b;
    5. public:
    6.     testClass_1(int _id);
    7.     ~testClass_1();
    8.     int get_a(void) { return a; };
    9.     int get_b(void) { return b; };
    10.  
    11.     void* operator new(size_t cb) {
    12.         MessageBox(NULL, "From testClass_1.operator new", NULL, MB_OK);
    13.         return (void*)HeapAlloc(activeHeap, 0, cb);    
    14.     };
    15. };
     
  6. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    GoldFinch
    Большое спасибо!
    Не ожидал, что компилятор сам сообразит в этом случае конструктор/деструктор вызвать :)
     
  7. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Вот что написал комо.

    Код (Text):
    1. "ComeauTest.c", line 10: error: assignment to "this" (anachronism)
    2.             this = (T*)malloc(sizeof(T));
    3.             ^
    4.  
    5. 1 error detected in the compilation of "ComeauTest.c".
    6.  
    7. In strict mode, with -tused, Compile failed
    Может лучше закрыть конструкторы и создавать фабрикой? И то что нагородил Страуструп решается с помощью placement new.
     
  8. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Первый раз слышу, чтобы зысу можно было что-то присваивать. Откуда цитата? Может быть какой-нибудь древний стандарт?
     
  9. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    _DEN_
    http://www.helloworld.ru/texts/comp/lang/c/c3/gl5_2.htm см. вокруг 5.5.7
     
  10. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Y_Mur

    Бугага, теперь все ясно)))
     
  11. deLight

    deLight New Member

    Публикаций:
    0
    Регистрация:
    26 май 2008
    Сообщения:
    879
    а насчет RTTI?.. видимо в таком случае и думать не стоит
     
  12. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    RTTI? тут бы от CRT избавиться...
     
  13. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Свои классы заработали - красота :)) Теперь бы ещё чужие заставить...
    Код (Text):
    1. //==================================================================
    2. //  Простое тестирование GDI+
    3. #include <windows.h>
    4. #include <GdiPlus.h>
    5. #pragma comment(linker,"/ENTRY:main")
    6. #pragma comment(linker,"/NODEFAULTLIB")
    7. // в свойствах линкера: ввод -> дополнительные зависимости -> добавить GdiPlus.lib
    8. // #pragma comment(lib, "GdiPlus.lib") при NODEFAULTLIB не работает
    9.  
    10. // Глобальные переменные
    11. HINSTANCE   hInst;
    12. LPVOID      activeHeap;
    13. using namespace Gdiplus;
    14.  
    15. //  Попытка обмануть линковку CRT
    16. int _fltused = 0x9875;
    17.  
    18. void drawGDIp(void){
    19.     // Подготовительные вычисления
    20.     int scrW = GetSystemMetrics(SM_CXSCREEN);
    21.     int scrH = GetSystemMetrics(SM_CYSCREEN);
    22.     int const rW = 200;
    23.     int const rH = 200;
    24.     int rX = (scrW - rW)/2;
    25.     int rY = (scrH - rH)/2;
    26.  
    27.     Graphics graph(GetDC(0));
    28. //  graph.Clear(Color(255, 255, 255, 0));   // <- это безобразие работает
    29.  
    30.     SolidBrush yellowBrush(Color(255, 255, 255, 0));    // <- не хватает type_info::`vftable'
    31.     graph.FillRectangle(&yellowBrush, rX, rY, rW, rH);
    32.     Pen testPen(Color(255, 0, 255, 0), 1.5f);       // <- не хватает __fltused
    33.     graph.DrawLine(&testPen, rX, rY, rX+rW, rY+rH);
    34. }
    35.  
    36. //  Функция входа в программу
    37. int main(void) {
    38.  
    39.     // Начальные настройки   
    40.     hInst = GetModuleHandle(NULL);
    41.     activeHeap = GetProcessHeap();
    42.     // Инициализация GDI+.
    43.     GdiplusStartupInput gdiplusStartupInput;
    44.     ULONG_PTR           gdiplusToken;
    45.     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    46.  
    47.     // Тестовая отрисовка
    48.     drawGDIp();
    49.  
    50.     // Завершение программы
    51.     GdiplusShutdown(gdiplusToken);
    52.     return 0;
    53. }
    В GDI+ без CRT не хотят создаваться перья и кисти.
    В исходниках CRT нашёл int _fltused = 0x9875;, но простое добавление этого в свою программу не помогает - как правильно заставить компилятор искать этот символ в моей программе?

    С vftable похоже сложнее:
    Конечно можно переписать GdiPlus.h без "лишних констант" и без использования виртуальных функций, которые собственно там совершенно не обязательны, но может есть способ попроще?
    Наверняка и в других навороченных заголовках есть подобные проблемы.
     
  14. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    Нету никаких проблем
     
  15. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    censored
    Хочешь сказать, что у тебя приведённый код скомпилился при /NODEFAULTLIB в exe ~3кб ?
     
  16. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    Какой конкретно?
     
  17. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    Y_Mur
    type_info вообще к RTTI относится. Разве он нужен для GDI+? o_O
    Это вообще откуда и для чего? Если линкер требует такую переменную, то она наверняка extern "C" должна быть...
     
  18. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    maxdiver
    __fltused хочет иметь Pen testPen(Color(255, 0, 255, 0), 1.5f);
    extern "C" - спасибо помогло :)

    type_info::`vftable' требует линкер для SolidBrush yellowBrush(Color(255, 255, 255, 0));
    можно как нибудь глобально запретить GdiPlus.h юзать RTTI? или только детально разбираться - чего они там в этих заголовках наворочали?

    censored
    конечно #13 :))
     
  19. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    Прошу
     
  20. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    censored
    А поподробнее - какой компилятор? ключи?