что происходит, когда typeid (obj) компилируется - C ++

Недавно я использовал следующее в приложении, которое хорошо работает для моих нужд.

.htaccess

<IfModule mod_rewrite.c>
# enable rewrite engine
RewriteEngine On

# if requested url does not exist pass it as path info to index.php
RewriteRule ^$ index.php?/ [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?/$1 [QSA,L]
</IfModule>

index.php

foreach (explode ("/", $_SERVER['REQUEST_URI']) as $part)
{
    // Figure out what you want to do with the URL parts.
}
3
задан Pendyala 5 March 2019 в 18:48
поделиться

1 ответ

Вам не нужно создавать какие-либо объекты, создающие экземпляры MyTemplate1<T> в модуле компиляции, чтобы видеть объекты типа info, описывающие классы реализации этого шаблона, в глобальной таблице символов объектного файла. Вам нужно только сослаться на typeid такого класса: -

$ cat main.cpp
#include <typeinfo>

template<class T>
class MyTemplate1
{
public:
    T a;

    MyTemplate1(T other){
        a = other;
    }
};

int main(void)
{
    return (typeid(MyTemplate1<int>) == typeid(MyTemplate1<float>));
}

$ clang++ -Wall -c main.cpp
$ readelf -s -W main.o | grep MyTemplate1
     5: 0000000000000000    16 OBJECT  WEAK   DEFAULT   15 _ZTI11MyTemplate1IfE
     6: 0000000000000000    16 OBJECT  WEAK   DEFAULT   10 _ZTI11MyTemplate1IiE
     7: 0000000000000000    17 OBJECT  WEAK   DEFAULT   13 _ZTS11MyTemplate1IfE
     8: 0000000000000000    17 OBJECT  WEAK   DEFAULT    8 _ZTS11MyTemplate1IiE

$ c++filt _ZTI11MyTemplate1IfE
typeinfo for MyTemplate1<float>
$ c++filt _ZTI11MyTemplate1IiE
typeinfo for MyTemplate1<int>
$ c++filt _ZTS11MyTemplate1IfE
typeinfo name for MyTemplate1<float>
$ c++filt _ZTS11MyTemplate1IiE
typeinfo name for MyTemplate1<int>

Эти typeinfo объекты существуют, потому что, как прокомментировал @Peter, стандарт C ++ требует, чтобы typeid ссылается на объект статической длительности хранения

Что именно происходит под капотом?

Вы можете задаться вопросом: почему компилятор делает это typeinfo ] символы объекта слабые , а не просто глобальные? Почему он определяет их в разных разделах объектного файла? (разделы 10 и 15 моего объектного файла, разделы 2894 и 2899 вашего).

И если мы проверим, что еще находится в этих разделах:

$ readelf -s main.o | egrep '(10 |15 )'
     5: 0000000000000000    16 OBJECT  WEAK   DEFAULT   15 _ZTI11MyTemplate1IfE
     6: 0000000000000000    16 OBJECT  WEAK   DEFAULT   10 _ZTI11MyTemplate1IiE

, мы видим, что каждый объект является единственным в своем разделе. Почему так?

В моих main.o эти разделы 10 и 15:

$ readelf -t main.o | egrep '(\[10\]|\[15\])'
  [10] .rodata._ZTI11MyTemplate1IiE
  [15] .rodata._ZTI11MyTemplate1IfE

Каждый из них - только для чтения раздел данных в смысл:

__attribute__((section(.rodata._ZTI11MyTemplate1IiE)))
__attribute__((section(.rodata._ZTI11MyTemplate1IfE)))

, который не содержит ничего, кроме определения объекта, после которого он назван.

Компилятор предоставляет каждому из объектов раздел данных для всех себе по той же причине, по которой он создает символы WEAK. Ссылки на typeid(MyTemplate1<X>) для произвольного типа X могут быть сделаны в нескольких единицах перевода в пределах одной и той же связи, что #include определение MyTemplate1. Чтобы предотвратить сбой связи в таких случаях с ошибкой множественного определения , компилятор делает символы слабыми. Линкер будет допускать множественные определения слабого символа , разрешая все ссылки просто на первое определение, которое представляет себя, и игнорируя остальные. Посредством выделения уникального раздела данных (или функционального раздела, в зависимости от случая) определению каждого слабого символа, создающего экземпляр шаблона, компилятор дает компоновщику свободу отбрасывать любые избыточные секции данных или функций, которые определяют такой же слабый символ без риска побочного ущерба для программы. См.

$ cat MyTemplate1.hpp
#pragma once

template<class T>
class MyTemplate1
{
public:
    T a;

    MyTemplate1(T other){
        a = other;
    }
};

$ cat foo.cpp
#include "MyTemplate1.hpp"
#include <typeinfo>

int foo()
{
    return typeid(MyTemplate1<int>) == typeid(MyTemplate1<float>);
}

$ cat bar.cpp
#include "MyTemplate1.hpp"
#include <typeinfo>

int bar()
{
    return typeid(MyTemplate1<int>) != typeid(MyTemplate1<float>);
}

$ cat prog.cpp
extern int foo();
extern int bar();

int main()
{
    return foo() && bar();
}

Если мы скомпилируем:

$ clang++ -Wall -c prog.cpp foo.cpp bar.cpp

и ссылку (с некоторой диагностикой) следующим образом:

$ clang++ -o prog prog.o bar.o foo.o \
         -Wl,-trace-symbol=_ZTI11MyTemplate1IfE \
         -Wl,-trace-symbol=_ZTI11MyTemplate1IiE \
         -Wl,-Map=mapfile
/usr/bin/ld: bar.o: definition of _ZTI11MyTemplate1IfE
/usr/bin/ld: bar.o: definition of _ZTI11MyTemplate1IiE
/usr/bin/ld: foo.o: reference to _ZTI11MyTemplate1IfE
/usr/bin/ld: foo.o: reference to _ZTI11MyTemplate1IiE

ввод bar.o до foo.o ], то компоновщик выбирает определения из _ZTI11MyTemplate1I(f|i)E из bar.o и игнорирует определения из foo.o, разрешая ссылки в foo.o на определения из bar.o. И файл карты показывает:

mapfile (1)

...
Discarded input sections
...
 .rodata._ZTI11MyTemplate1IiE
                0x0000000000000000       0x10 foo.o
...
 .rodata._ZTI11MyTemplate1IfE
                0x0000000000000000       0x10 foo.o
...

, что определения в foo.o были отброшены. Если мы свяжемся с порядком bar.o и foo.o в обратном порядке:

$ clang++ -o prog prog.o foo.o bar.o \
             -Wl,-trace-symbol=_ZTI11MyTemplate1IfE \
             -Wl,-trace-symbol=_ZTI11MyTemplate1IiE \
             -Wl,-Map=mapfile
/usr/bin/ld: foo.o: definition of _ZTI11MyTemplate1IfE
/usr/bin/ld: foo.o: definition of _ZTI11MyTemplate1IiE
/usr/bin/ld: bar.o: reference to _ZTI11MyTemplate1IfE
/usr/bin/ld: bar.o: reference to _ZTI11MyTemplate1IiE

, то мы получим противоположные результаты. Определения из foo.o связаны между собой:

mapfile (2)

...
Discarded input sections
...
 .rodata._ZTI11MyTemplate1IiE
                0x0000000000000000       0x10 bar.o
...
 .rodata._ZTI11MyTemplate1IfE
                0x0000000000000000       0x10 bar.o
...

из bar.o выброшены. Этот принцип компоновки «первым пришел - первым обслужен» хорош, потому что - и только , потому что - определение template<class T> MyTemplate1, которое компилятор нашел в блоке перевода foo.cpp, было идентично ] к тому, которое было найдено в bar.cpp, условие, которое стандарт C ++ требует , в правило единого определения , но которое компилятор C ++ ничего не может сделать для принудительного применения .

Вы можете сделать, в основном, те же самые наблюдения относительно символов создания шаблона в целом, и то, что вы видите с помощью clang ++, по сути то же самое, что вы увидите с g ++.

0
ответ дан Mike Kinghan 5 March 2019 в 18:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: