int main()
{
return 0;
}
Глюк линкеров C++
Имеется три файла:
Файл 1:
Код:
Файл 2:
Код:
#include <iostream>
class Class {
public:
Class() { std::cout << "Module1: Class::Class();" << std::endl; }
} c1;
class Class {
public:
Class() { std::cout << "Module1: Class::Class();" << std::endl; }
} c1;
Файл 3:
Код:
#include <iostream>
class Class {
public:
Class() { std::cout << "Module2: Class::Class();" << std::endl; }
} c2;
class Class {
public:
Class() { std::cout << "Module2: Class::Class();" << std::endl; }
} c2;
Экземпляры c1 и с2 можно было бы создавать и внутри некоторой функции модуля и вызывать их из основного - от этого эффект не изменится.
А фокус заключается в том, что для обоих объектов c1 и c2 будет вызван один и тот же конструктор. У меня, например, такой вывод:
Module1: Class::Class();
Module1: Class::Class();
Я решил немного поэкспериментировать на двух компиляторах и вот что получилось:
MSVC 6.0,8.0:
Если один из конструкторов подставляемый (определенный с директивой inline или определен
в объявлении класса, как в примере), а другой нет, то выкидывается ошибка линковки.
Если же сделать все тоже самое, но для метода, то все в порядке.
gcc-3.3.3:
Отличий для конструктора и метода нет.
Программа не линкуется только тогда, когда оба конструктора или метода неподставляемые.
А теперь то, как этого можно избежать не изменяя имен классов.
Для этого применяем современную альтернативу static - namespace.
Объявления классов заносятся в анонимное пространство и спокойно используются внутри своей единицы трансляции.
Из этого можно сделать следующий вывод: объявляйте конструкции локального использования внутри анонимных
пространств имен, а внешние - в именных. Было бы не приятно, если подобного рода штука выскочила из-за совпадения
имени вашего класса с другим из сторонней библиотеки.
Файл 2:
Код:
#include <iostream>
namespace {
class Class {
public:
Class() { std::cout << "Module1: Class::Class();" << std::endl; }
} c1;
} // namespace {
namespace {
class Class {
public:
Class() { std::cout << "Module1: Class::Class();" << std::endl; }
} c1;
} // namespace {
Файл 3:
Код:
#include <iostream>
namespace {
class Class {
public:
Class() { std::cout << "Module2: Class::Class();" << std::endl; }
} c2;
} // namespace
namespace {
class Class {
public:
Class() { std::cout << "Module2: Class::Class();" << std::endl; }
} c2;
} // namespace
Для работоспособности, конечно, достаточно определить одно пространство, но я такой методики стараюсь
придерживаться всегда. И благо, что я наткнулся на этот баг не в реальном проекте, а когда от безделья на работе игрался с компилятором.
Может кто-то пояснит механизм получения такого результата?
А теперь представим идиотов, создающих оптимизирующий компилятор и линкер, производящие дохлый код.