![](/img/trans.png)
[英]clang compiled program throws std::bad_any_cast during std::any_cast
[英]std::any_cast throws a bad any_cast error when converting void* to function pointer
我寫了下面的代碼,
std::unordered_map<std::string_view, std::any> symbols_;
symbols_["foo"] = dlsym(handle_), "foo");
當我使用 any_cast return (std::any_cast<void(*)()>(symbols_["foo"]))();
,程序會拋出錯誤:bad any_cast。
我找到了主要原因,因為功能。
template<typename _Tp>
void* __any_caster(const any* __any)
它會判斷條件為假,然后返回 nullptr。
else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage
#if __cpp_rtti
|| __any->type() == typeid(_Tp)
#endif
){
any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg);
return __arg._M_obj;
}
return nullptr;
我想知道
1.為什么__any->_M_manager == &any::_Manager<_Up>::_S_manage
和__any->type() == typeid(_Tp)
都是假的,
2.我該如何解決這個問題(繼續使用 std::any)。
這是一個簡單的演示。
#include <any>
void func() { }
auto main() -> int {
std::any a = (void*)func;
std::any_cast<void(*)()>(a)();
return 1;
}
gcc 版本 10.1.0 (GCC)
在這里,您將void*
存儲在std::any
對象中:
symbols_["foo"] = dlsym(handle_, "foo");
要存儲void(*)()
,您需要轉換dlsym
返回的void*
:
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_, "foo"));
在這種情況下,您可能只想存儲void*
並在使用它時進行轉換:
std::unordered_map<std::string_view, void*> symbols_;
symbols_["foo"] = dlsym(handle_, "foo");
//...
return reinterpret_cast<void(*)()>(symbols_["foo"])();
如果您不需要在unordered_map
進行運行時查找,則第三個選項是將函數指針存儲在命名變量中。 這使得使用更容易一些。 下面是一個例子:
用於加載/卸載共享庫的通用class
:
class Lib {
public:
explicit Lib(const char* filename, int flags = RTLD_LAZY) :
lib(dlopen(filename, flags))
{
if(!lib) throw std::runtime_error(dlerror());
}
Lib(const Lib&) = delete;
Lib(Lib&& rhs) = delete;
Lib& operator=(const Lib&) = delete;
Lib& operator=(Lib&& rhs) = delete;
virtual ~Lib() { dlclose(lib); }
private:
struct cast_proxy { // a class to cast to the proper pointer
// cast to whatever that is needed:
template<class Func>
operator Func () { return reinterpret_cast<Func>(sym); }
void* sym;
};
protected:
cast_proxy sym(const char* symbol) const {
void* rv = dlsym(lib, symbol);
if(rv) return {rv}; // put it in the cast_proxy
throw std::runtime_error(dlerror());
}
private:
void* lib;
};
用於加載特定共享庫的類:
class YourLib : public Lib {
public:
YourLib() : Lib("./libyour_library.so"),
// load all symbols here:
foo(sym("foo")) // the cast proxy will return the correct pointer type
{}
// Definitions of all the symbols you want to load:
void(*const foo)();
};
然后使用它將像這樣簡單:
int main() {
YourLib ml;
ml.foo();
}
std::any_cast
只會轉換回存儲在std::any
。 由於dlsym
返回void*
,這就是存儲在std::any
。
在存儲在std::any
或在std::any_cast
之后,您需要對void(*)()
進行單獨的std::any_cast
:
std::unordered_map<std::string_view, std::any> symbols_;
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_), "foo"));
return (std::any_cast<void(*)()>(symbols_["foo"]))();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.