動的にロードされたライブラリ(dlopenなどでロードされた)が実際に独自の新しい削除演算子を使用し、呼び出し元のプログラムで定義されたものではないことを確認したかったのです。だから私は次のlibrary.cppを書きました
#include <exception>
#include <new>
#include <cstdlib>
#include <cstdio>
#include "base.hpp"
void* operator new(size_t size) {
std::printf("New of library called\n");
void *p=std::malloc(size);
if (p == 0) // did malloc succeed?
throw std::bad_alloc(); // ANSI/ISO compliant behavior
return p;
}
void operator delete(void* p) {
std::printf("Delete of library called\n");
std::free(p);
}
class Derived : public Base {
public:
Derived() : Base(10) { }
};
extern "C" {
Base* create() {
return new Derived;
}
void destroy(Base* p) {
delete p;
}
}
でコンパイルしました
g++ -g -Wall -fPIC -shared library.cpp -o library.so
または雇用されたロシア人が試みることを提案したように(しかし結局何も変わらなかった)
g++ -g -Wall -fPIC -shared -Wl,-Bsymbolic library.cpp -o library.so
クラスBaseは、この値を取得するためにint値と関数get_value()のみを保持しています。その後、client.cppをこのように書きました
#include <exception>
#include <new>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <dlfcn.h>
#include "base.hpp"
void* operator new(size_t size) {
std::printf("New of client called\n");
void *p=std::malloc(size);
if (p == 0) // did malloc succeed?
throw std::bad_alloc(); // ANSI/ISO compliant behavior
return p;
}
void operator delete(void* p) {
std::printf("Delete of client called\n");
std::free(p);
}
typedef Base* create_module_t();
typedef void destroy_module_t(Base *);
int main() {
void* handle = dlopen("./library.so",
RTLD_LAZY);
if (handle == NULL) {
std::cout << dlerror() << std::endl;
return 1;
}
create_module_t* create_module = NULL;
void* func = dlsym(handle, "create");
if (func == NULL) {
std::cout << dlerror() << std::endl;
return 1;
} else create_module = (create_module_t *)func;
destroy_module_t* destroy_module = NULL;
func = dlsym(handle, "destroy");
if (func == NULL) {
std::cout << dlerror() << std::endl;
return 1;
} else destroy_module = (destroy_module_t *)func;
Base* a = create_module();
std::cout << "Value: " << a->get_value() << std::endl;
destroy_module(a);
return 0;
}
でコンパイルしました
g++ -Wall -g -o client -ldl client.cpp
クライアントを実行すると、「呼び出されたクライアントの新規」と「呼び出されたクライアントの削除」のみが表示されます。コンパイラスイッチ-Bsymbolicをライブラリに使用しても、EmployedRussianが提案しました。
今:何が悪かったのですか?共有ライブラリは独自のnew/deleteを使用していると思ったので、ファクトリの隣にライブラリコードでデストラクタdestroyを作成するように指定する必要があります。
補足質問:destroy(Base * p)関数が必要なのはなぜですか?この関数がクライアントのdelete-operatorのみを呼び出す場合は、自分でそれを行うこともできます。つまり、最後の行の次のdestroy_module(a)の代わりに「deletea」を実行します。
私が見つけた回答:ライブラリは、new/delete-operatorのペアも提供できます。したがって、最初にライブラリの新しいものを使用し、後でクライアントの削除を使用すると、おそらく落とし穴に踏み込むことができます。悲しいことに、これまで、自分のライブラリが独自の新規または削除を使用しているのを見たことがありませんでした...したがって、元の質問にはまだ回答されていません。
補足:私はLinuxプラットフォームについてのみ言及しています。
編集:重要な部分は、雇用されたロシアの回答へのコメントにあります。だから私は一言で言えば主な手がかりを与えています:このようにgccを呼び出す場合
g++ -Wall -g -fPIC -shared library.cpp -o library.so -Wl,-Bsymbolic
ライブラリは独自のnew/delete演算子を使用します。そうでなければ結果
g++ -Wall -g -fPIC -shared library.cpp -o library.so
呼び出し側プログラムのnew/delete演算子を使用しているライブラリー内。雇用されたロシア人に感謝します!