나는 "카탈로그"접근법을 사용하여 객체 할당에 다소 관여하는 접근법을 사용합니다. 코드는 파생 된 객체를 가리키는 기본 포인터로 채워지는 카탈로그 객체 (전역 정적지도)를 생성합니다. 이것은 모두 불경 스럽지만 여기에 요점은 아닙니다. 프로그램 실행시, 카탈로그는 모든 파생 된 오브젝트로 채워지며 후보 파생 된 클래스 목록을 유지할 필요없이 카탈로그에 등록 된 모든 것을 할당 할 수 있습니다. 큰. 그러나 파생 클래스 중 하나가 아카이버 (ar)를 통해 실행되고 링커의 오브젝트 파일 대신 아카이브가 사용되면 코드가 실패합니다. 누군가 이것이 왜 이런 일이 일어 났는지 말해 줄 수 있습니까? 예제 코드 :아카이버 (ar)가 오브젝트 파일과 동일하게 동작하는 아카이브를 생성하도록하는 방법은 무엇입니까?
//Base.h
#include<unordered_map>
#include<string>
#include<map>
#include<iostream>
#include<memory>
class Base
{
public:
Base(std::string name):m_name(name){}
virtual ~Base() {}
std::string m_name;
};
class ObjectCatalogueEntryBase
{
public:
typedef std::map< std::string, ObjectCatalogueEntryBase* > CatalogueType;
ObjectCatalogueEntryBase(){}
virtual std::unique_ptr<Base> Allocate(std::string const &) = 0;
virtual ~ObjectCatalogueEntryBase(){}
static CatalogueType& GetCatalogue()
{
static CatalogueType catalogue;
return catalogue;
}
static std::unique_ptr<Base> Factory(const std::string& objectTypeName, std::string const & name)
{
std::cout<<"Creating solver of type: "<<objectTypeName<<" name "<<name<<std::endl;
ObjectCatalogueEntryBase* const entry = GetCatalogue().at(objectTypeName);
return entry->Allocate(name);
}
};
template< typename TYPE >
class ObjectCatalogueEntry : public ObjectCatalogueEntryBase
{
public:
ObjectCatalogueEntry():
ObjectCatalogueEntryBase()
{
std::string name = TYPE::CatalogueName();
(ObjectCatalogueEntryBase::GetCatalogue())[name] = this;
std::cout<<"Registered Solver: "<<name<<std::endl;
}
~ObjectCatalogueEntry() final{}
virtual std::unique_ptr<Base> Allocate(std::string const & name) final
{
return std::unique_ptr<Base>(new TYPE(name));
}
};
/// Compiler directive to simplify autoregistration
#define REGISTER_FACTORY(ClassName) namespace{ ObjectCatalogueEntry<ClassName> reg_; }
다음 파일 :
// Derived.h
#include "Base.h"
class Derived : public Base
{
public:
Derived(std::string name);
~Derived();
static std::string CatalogueName() {return "Derived";}
};
다음 파일 :
// Derived.cpp
#include "Derived.h"
Derived::Derived(std::string name):Base(name)
{}
Derived::~Derived()
{}
REGISTER_FACTORY(Derived)
다음 파일 :
// main.cpp
#include "Derived.h"
int main()
{
std::string newName("Foo");
auto solver = ObjectCatalogueEntryBase::Factory(Derived::CatalogueName(),newName);
return 0;
}
그리고 메이크 :
CPP=g++-mp-6
test: main.o Derived.o
${CPP} -std=c++14 -o test main.o Derived.o
testlib: main.o Derived.a
${CPP} -std=c++14 -o testlib main.o Derived.a
main.o: main.cpp Base.h Derived.h
${CPP} -std=c++14 -c main.cpp
Derived.o: Derived.cpp Derived.h
${CPP} -std=c++14 -c Derived.cpp
Derived.a:
ar qcsv Derived.a Derived.o
clean:
rm *.o *.a test testlib
all: test testily
그래서 두 개의 실행 파일이 링크됩니다. 첫번째 (시험) 오브젝트 파일과 연계하여 "올바른"결과 생성된다으로 만들어진 Derived.a로 대체 Derived.o 파일과 연결된
$ ./test
Registered Solver: Derived
Creating solver of type: Derived name Foo
두번째 (testlib)를 Derived.o만을 사용하는 "ar". 결과는 다음과 같습니다.
./testlib
Creating solver of type: Derived name Foo
terminate called after throwing an instance of 'std::out_of_range'
what(): map::at
Abort trap: 6
분명히 등록이 발생하지 않았으며지도가 비어 있습니다. gcc6과 apple clang7에서 같은 결과가 나타납니다. 나는 그것이 전역 정적지도와 관련이 있다고 의심하지만, "ar"이 객체 파일에서 무엇을 제거하고 있는지를 충분히 이해하지 못한다. 따라서 두 가지 질문이 있습니다.
- 왜 아카이브 버전이 실패합니까?
- 링커 관점에서 볼 때 객체 파일과 동일한 모양의 아카이브 파일을 생성하려면 어떻게해야합니까?
darwin (mac osx)에서 시스템 링커에는 "--whole-archive"가 없습니다. 대신 작동하는 것처럼 보이는 "-all_load"명령이 있습니다. 감사! – doc07b5