4

ランタイムにロードされた共有ライブラリでインスタンス化されたオブジェクトでdynamic_castを使用する際に問題が発生しましたが、クラスに別のメソッドをオーバーライドするメソッドが含まれている場合に限ります。

「AppleLLVM3.1コンパイラ」でXcode4.3を使用しています。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の両方が真になることを期待しています。

誰かがこれを見たことがありますか、または回避策を考えることができますか?

4

2 に答える 2

0

この問題の原因は 2 つあります。まず、動的キャストは RTTI オブジェクトで等価比較を使用しています。次に、メインラインに 1 つと動的ライブラリに 1 つの 2 つがあります。

この問題の回避策は、共有するクラスが別のダイナミック リンク ライブラリにあり、メインラインと他のすべての共有ライブラリの両方からリンクされていることを確認することです。

本当にライブラリ/コンパイラのバグです。動的な型比較にポインタの等価性を使用すべきではありません。


おっとっと。私はこれを試しましたが、問題は解決しませんでした (g++ もこれを台無しにしていた)。奇妙なことに、別のライブラリで例外を正しくキャッチし、再スローし、基本クラスのポインターを介して正しくキャッチしていますが、dynamic_cast は失敗しています。したがって、私の推奨事項は (OSX 上で) 機能していないようです。ごめん。

于 2012-09-01T05:30:28.310 に答える
0

から別のアプリケーションに渡す場合は、C++ クラスの実装コードに静的ライブラリを使用できません.dylib。共有オブジェクトを使用する必要があります。

その理由は、リンク時に と の両方に型情報のプライベート コピーが作成されるためlibtest2.dylibですtest1。そして、それらは互いに互換性がなくなります。

機能させたい場合は、 と application の両方にリンクされているtest3.cpp/hからクラスをエクスポートする必要があります。.dyliblibtest2.dylibtest1

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
于 2012-09-01T15:43:27.430 に答える