Да, Вы правы. Но суть в том, что многие не задумываются об этом до тех пор, пока не возникнут проблемы. У довольно большого числа людей психология в духе «зачем мне знать, как это устроено, если все и так работает?».
«Миф» выделен полужирным в тексте и состоит в том, что все-таки не всегда удается «безболезненно» определить inline-метод вне объявления класса. Эккель, к примеру, пишет, что в отличие от обычных методов, inline-методы нужно определять прямо в хедере, но мой мозг благополучно «пропустил» этот факт и вспомнил о нем лишь тогда, когда столкнулся на практике.
Для Вас, видимо, это не миф, а многие до сих пор об этом не подозревают.
А вообще не нужно относиться к слову «миф», как к ключевому. Я об этом писал: «Оно [название], естественно, появилось не случайно, однако и не совсем соответствует сути».
> «По стандарту адрес будет в любом случае. А формат ф-ции(встроит ее компилятор или нет) будет зависеть от настроек этого самого компилятора. Вобще современные компиляторы и компоновщики дело темное и зачастую они игнорируют указания программиста».
Компилируем в MS Visual Studio c ключом /Ob1 (это Inline Function Expansion: Only __inline) в релизной конфигурации следующий код: // A.h
В месте вызова метода по-прежнему была подстановка. НО! Там, где мы получаем адрес метода и используем его, стоит call. По этому адресу появилось вот что:
> Нет, ф-ция будет иметь адрес.
Если у нас где-нибудь будет выполняться операция взятия адреса данной функции, компилятор проигнорирует ключевое слово inline и скомпилирует функцию в обычной форме.
>Тут небудет двойного определения, вы в объявлении класса объявите inline метод, а потом определите его. Все по чесному, никаких отключений проверок.
Допустим, у нас есть хедер A.h, в котором объявлен класс A с inline-методом, определение которого находится в том же хедере.
Этот хедер мы инклудим в файлы B.cpp и C.cpp, которые представляют собой отдельные единицы трансляции и на стадии компиляции образовывают отдельные объектные файлы.
При сборке оба файла попадают в бинарник, а значит там будет двойное определение. Или я что-то неправильно понимаю?
Для Вас, видимо, это не миф, а многие до сих пор об этом не подозревают.
А вообще не нужно относиться к слову «миф», как к ключевому. Я об этом писал: «Оно [название], естественно, появилось не случайно, однако и не совсем соответствует сути».
А вот Вы, как и многие другие, заигнорили мой совет: «Профессионалам … можно дальше не читать» :) Не в обиду.
> Плюсы:
> наиболее полная поддежка xmpp протокола
Да Miranda вроде тоже не мало расширений протокола xmpp поддерживает: список
Компилируем в MS Visual Studio c ключом /Ob1 (это Inline Function Expansion: Only __inline) в релизной конфигурации следующий код:
// A.h
#ifndef _A_H_
#define _A_H_
#include <iostream>
class A
{
public:
inline void foo();
};
void A::foo()
{
std::cout << "A::foo()" << std::endl;
}
// main.cpp
#include <cstdlib>
#include <iostream>
#include "A.h"
int main()
{
A a;
a.foo();
return EXIT_SUCCESS;
}
Смотрим Disassembly:
int main()
{
A a;
a.foo();
00401000 mov ecx,dword ptr [__imp_stlp_std::cout (4020ACh)]
00401006 push esi
00401007 push offset string "A::foo()" (402114h)
0040100C mov esi,ecx
0040100E call dword ptr [__imp_stlp_std::basic_ostream<char,stlp_std::char_traits<char> >::_M_put_nowiden (4020B0h)]
00401014 push offset stlp_std::endl<char,stlp_std::char_traits<char> > (401030h)
00401019 mov ecx,esi
0040101B call dword ptr [__imp_stlp_std::basic_ostream<char,stlp_std::char_traits<char> >::operator<< (4020A4h)]
Inline-метод был подставлен на место вызова. Ни кода метода, ни вообще класса в бинарнике нет.
Отредактируем main.cpp:
// main.cpp
#include <cstdlib>
#include <iostream>
#include "A.h"
int main()
{
A a;
a.foo();
void (A::*pF)() = &A::foo; // берем адрес подставляемого метода
(a.*pF)(); // используем
return EXIT_SUCCESS;
}
Снова смотрим Disassembly:
int main()
{
00401030 push ecx
A a;
a.foo();
00401031 mov ecx,dword ptr [__imp_stlp_std::cout (4020ACh)]
00401037 push esi
00401038 push offset string "A::foo()" (402114h)
0040103D mov esi,ecx
0040103F call dword ptr [__imp_stlp_std::basic_ostream<char,stlp_std::char_traits<char> >::_M_put_nowiden (4020B0h)]
00401045 push offset stlp_std::endl<char,stlp_std::char_traits<char> > (401060h)
0040104A mov ecx,esi
0040104C call dword ptr [__imp_stlp_std::basic_ostream<char,stlp_std::char_traits<char> >::operator<< (4020A4h)]
void (A::*pF)() = &A::foo;
(a.*pF)();
00401052 lea ecx,[esp+7]
00401056 call A::foo (401000h)
В месте вызова метода по-прежнему была подстановка. НО! Там, где мы получаем адрес метода и используем его, стоит call. По этому адресу появилось вот что:
void A::foo()
{
std::cout << "A::foo()" << std::endl;
00401000 mov ecx,dword ptr [__imp_stlp_std::cout (4020ACh)]
00401006 push esi
00401007 push offset string "A::foo()" (402114h)
0040100C mov esi,ecx
0040100E call dword ptr [__imp_stlp_std::basic_ostream<char,stlp_std::char_traits<char> >::_M_put_nowiden (4020B0h)]
00401014 push offset stlp_std::endl<char,stlp_std::char_traits<char> > (401060h)
00401019 mov ecx,esi
0040101B call dword ptr [__imp_stlp_std::basic_ostream<char,stlp_std::char_traits<char> >::operator<< (4020A4h)]
00401021 pop esi
}
То есть, тело метода все-таки было сгенерировано отдельно!
> «Два определения приемлимы если…»
Но ведь определения все-таки два! ;) Сойдемся на том, что конфликта здесь не возникает.
Если у нас где-нибудь будет выполняться операция взятия адреса данной функции, компилятор проигнорирует ключевое слово inline и скомпилирует функцию в обычной форме.
>Тут небудет двойного определения, вы в объявлении класса объявите inline метод, а потом определите его. Все по чесному, никаких отключений проверок.
Допустим, у нас есть хедер A.h, в котором объявлен класс A с inline-методом, определение которого находится в том же хедере.
Этот хедер мы инклудим в файлы B.cpp и C.cpp, которые представляют собой отдельные единицы трансляции и на стадии компиляции образовывают отдельные объектные файлы.
При сборке оба файла попадают в бинарник, а значит там будет двойное определение. Или я что-то неправильно понимаю?