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

Discussion in 'LANGS.C' started by sn0w, Aug 27, 2018.

  1. sn0w

    sn0w Active Member

    Blog Posts:
    0
    Joined:
    Feb 27, 2010
    Messages:
    958
    VisualStudio 2017 15.8.1
    есть модуль a.cpp с кодом:
    Code (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 с кодом:
    Code (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

    Blog Posts:
    0
    Joined:
    Feb 27, 2010
    Messages:
    958
    тоже самое и с методами. только единсна - по какойто причине компилер в модуле а не генерит кода, а в б генерит. и референц с а идёт в б.
     
  3. f1redArk

    f1redArk Member

    Blog Posts:
    0
    Joined:
    Jul 10, 2008
    Messages:
    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 Владимир Садовников

    Blog Posts:
    8
    Joined:
    Jun 4, 2007
    Messages:
    1,610
    Location:
    г. Санкт-Петербург
    Это всё следствие того, что инстанцированные темплейты надо как-то компоновать так, чтобы они не дублировались. Короче, типа фича, а не баг со стороны C++.
     
  5. SadKo

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

    Blog Posts:
    8
    Joined:
    Jun 4, 2007
    Messages:
    1,610
    Location:
    г. Санкт-Петербург
    Нашёл возможное решение для вас - оберните класс в анонимный неймспейс, и будет счастье:
    Code (Text):
    1.  
    2. namespace {
    3.     class Foo { /* ... */ }
    4. }
    5. [code]
     
  6. sn0w

    sn0w Active Member

    Blog Posts:
    0
    Joined:
    Feb 27, 2010
    Messages:
    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

    Blog Posts:
    0
    Joined:
    Feb 27, 2010
    Messages:
    958
    SadKo

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

    f1redArk

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