只有当类重写方法时,在动态加载的共享库中实例化的类才会丢失XCode 4.3/4.4 typeinfo

XCode 4.3/4.4 typeinfo is lost for class instantiated in a dynamically loaded shared library only if class overrides a method

本文关键字:实例化 XCode typeinfo 共享 方法 重写 加载 动态      更新时间:2023-10-16

我在运行时加载的共享库中实例化的对象上使用dynamic_cast遇到了一个问题,但前提是该类包含覆盖另一个方法的方法。

我将Xcode 4.3与"Apple LLVM 3.1编译器"一起使用。我在linux上用gcc和clang编译了相同的代码,但没有问题,所以我认为这是Xcode中的编译器错误,但以前有人见过吗?

假设类定义在名为"test3.h"的头中

#pragma once
class c1
{
public:
 virtual ~c1 ();
 virtual void foo ();
};
class c2 : public c1
{
public:
 void foo () override;
};
class c3 : public c1
{
public:
};

假设实现代码位于名为"test3.cpp"的源文件中的静态库中

#include "test3.h"
c1::~c1 ()
{
}
void c1::foo ()
{
}
void c2::foo ()
{
}

假设一个名为test2.cpp 的源文件中有一个简单的动态库

#include "test3.h"
extern "C"
c1 * get1 ()
{
 return new c2;
}
extern "C"
c1 * get2 ()
{
 return new c3;
}

假设源文件test1.cpp 中有一个简单的可执行应用程序

#include "test3.h"
#include <dlfcn.h>
#include <iostream>
int main ()
{
 auto lib (dlopen ("libtest2.dylib", RTLD_NOW | RTLD_GLOBAL));
 auto a1 (dlsym (lib, "get1"));
 auto a2 (dlsym (lib, "get2"));
 auto f1 ((c1 * (*) ())a1);
 auto f2 ((c1 * (*) ())a2);
 auto o1 (f1 ());
 auto o2 (f2 ());
 auto d1 (dynamic_cast <c2 *> (o1));
 auto d2 (dynamic_cast <c3 *> (o2));
 auto result1 (d1 != 0);
 auto result2 (d2 != 0);
 std::cout << result1 << std::endl;
 std::cout << result2 << std::endl;
}

运行测试程序时,result1为false,而result2为true。我希望result1和result2都是真的。

有人看到这一点吗?或者能想出一个变通办法吗?

我认为这个问题的原因有两个。首先,动态强制转换在RTTI对象上使用相等比较。其次,有两个:一个在主线中,一个在动态库中。

这个问题的解决方法应该是确保要共享的类在一个单独的动态链接库中,并且由主线和所有其他共享库链接到。

实际上,这是库/编译器中的一个错误:它不应该使用指针相等来进行动态类型比较。


哎呀。我试过这个,但它并没有解决我的问题(g++过去也把它搞砸了)。奇怪的是,我在另一个库中正确地捕获了一个异常,重新思考它,通过基类指针正确地捕获它,但dynamic_cast失败了。因此,我的建议(在OSX上)似乎不起作用。很抱歉

如果您打算将c++类的实现代码从.dylib传递到另一个应用程序,则不能使用静态库来实现这些类——您必须使用共享对象。

原因是在链接时,您最终会在libtest2.dylibtest1中获得类型信息的私有副本;并且它们将彼此不兼容。

如果要使其工作,则需要在链接到libtest2.dylib和应用程序test1.dylib中从test3.cpp/h导出类。

示例Makefile:

CXX=clang
CXXFLAGS=-std=c++11
all: libshlib.dylib libtest2.dylib test1
clean:
    rm -f *.o test1 *.dylib
test3.o: test3.cpp test3.h
    $(CXX) $(CXXFLAGS) -c -fPIC test3.cpp -o test3.o
libshlib.dylib: test3.o
    $(CXX) $(CXXFLAGS) -fPIC -shared test3.o -o $@ -lstdc++
test2.o: test2.cpp test3.h
    $(CXX) $(CXXFLAGS) -c -fPIC test2.cpp -o test2.o
libtest2.dylib: libshlib.dylib test2.o
    $(CXX) $(CXXFLAGS) -o $@ -shared test2.o -lstdc++ -L. -lshlib
test1: test1.o test3.h
    $(CXX) $(CXXFLAGS) -o $@ test1.o -lstdc++ -L. -lshlib
test1.o: test1.cpp test3.h
    $(CXX) $(CXXFLAGS) -c -o $@ test1.cpp