коллизия noinline конструктора

Тема в разделе "LANGS.C", создана пользователем sn0w, 27 авг 2018.

  1. sn0w

    sn0w Active Member

    Публикаций:
    0
    Регистрация:
    27 фев 2010
    Сообщения:
    958
    VisualStudio 2017 15.8.1
    есть модуль a.cpp с кодом:
    Код (Text):
    1.   class Foo
    2.   {
    3.   public:
    4.     int a = 5;
    5.  
    6.     __declspec(noinline)Foo() {__debugbreak();};
    7.  
    8.   };
    9.  
    10. void test_2()
    11. {
    12.   {
    13.     __debugbreak();
    14.     Foo d;
    15.     ++d.a;
    16. }
    17. }
    и есть модуль b.cpp с кодом:
    Код (Text):
    1. class Foo
    2. {
    3. public:
    4.     int a = 1;
    5.     int b = 2;
    6.     int c = 3;
    7.  
    8.     __declspec(noinline) Foo() { cout << "ctor()\n"; }
    9.     __declspec(noinline) Foo(Foo&) { cout << "c_ctor()\n"; }
    10.     __declspec(noinline) ~Foo() { cout << "dtor()\n"; }
    11.     Foo& operator=(const Foo&) { cout << "assignment op\n"; }
    12.  
    13.     Foo(int, int, int);
    14. };//...
    линкуются вместе, ошибок нет. при отработке
    void test_2() вызывается конструктор из файла b.cpp, конечно решается обёртеой Foo в любой неймспейс, но вообще я ожидал что линкер ругнётся на редеф конструктора...
     
  2. sn0w

    sn0w Active Member

    Публикаций:
    0
    Регистрация:
    27 фев 2010
    Сообщения:
    958
    тоже самое и с методами. только единсна - по какойто причине компилер в модуле а не генерит кода, а в б генерит. и референц с а идёт в б.
     
  3. f1redArk

    f1redArk Member

    Публикаций:
    0
    Регистрация:
    10 июл 2008
    Сообщения:
    34
    А почему он должен ругнуться? У вас тут UB, и можно случиться вообще все что угодно. По умолчанию компилятор предполагает, что если он видит 2 и более определения одного и того же класса, то они идентичны) Стоит почитать про ODR:

    Only one definition of any variable, function, class type, enumeration type, concept (since C++20) or template is allowed in any one translation unit (some of these may have multiple declarations, but only one definition is allowed).

    There can be more than one definition in a program, as long as each definition appears in a different translation unit, of each of the following: class type, enumeration type, inline function with external linkage inline variable with external linkage (since C++17), class template, non-static function template, static data member of a class template, member function of a class template, partial template specialization, concept, (since C++20) as long as all of the following is true:

    • each definition consists of the same sequence of tokens (typically, appears in the same header file)
    • ...
    If all these requirements are satisfied, the program behaves as if there is only one definition in the entire program. Otherwise, the behavior is undefined.
     
  4. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Это всё следствие того, что инстанцированные темплейты надо как-то компоновать так, чтобы они не дублировались. Короче, типа фича, а не баг со стороны C++.
     
  5. SadKo

    SadKo Владимир Садовников

    Публикаций:
    8
    Регистрация:
    4 июн 2007
    Сообщения:
    1.610
    Адрес:
    г. Санкт-Петербург
    Нашёл возможное решение для вас - оберните класс в анонимный неймспейс, и будет счастье:
    Код (Text):
    1.  
    2. namespace {
    3.     class Foo { /* ... */ }
    4. }
    5. [code]
     
  6. sn0w

    sn0w Active Member

    Публикаций:
    0
    Регистрация:
    27 фев 2010
    Сообщения:
    958
    вот еще кстати, проверял на микромягком:
    class SampleClass
    {
    public:
    __declspec(noinline) void Message(char* d)
    {
    MessageBoxW(0, 0, 0, 0);
    }
    };

    пилим это в 2 модуля, компилим и линкуем их. и нету ошибок линкера о редефе, хотя каждый объектник содержит идентично замангленный Message притом в секции PUBLIC.
    тут либо я хреново маны курнул, либо так и должно быть. ну и само собой каждый модуль будет прилинковывать "свой" экземпляр. если имплементацию в одном снести - прилинкует оную с другого модуля.
    единственно что не проверил - 3 модуля: в двух с noinline inclass definition а в третьем - только декларация. кого слинкует.
     
  7. sn0w

    sn0w Active Member

    Публикаций:
    0
    Регистрация:
    27 фев 2010
    Сообщения:
    958
    SadKo

    , спс, но
    просто пробую различные вариации разного с разным. а насчёт анонимного ns - там тоже интересно, один компилер запиливает в объектниках всё как static другой - нет

    f1redArk

    да понятно, руководствуюсь cppreference разумеется, просто как уже написал - миксую, смотрю на реализацию
     
    Последнее редактирование: 27 сен 2018