代码之家  ›  专栏  ›  技术社区  ›  Michał Walenciak

clang编译程序在std::any_cast期间抛出std::bad_any_cast

  •  4
  • Michał Walenciak  · 技术社区  · 6 年前

    我正在开发一个应用程序 std::any .

    最近我发现当我用clang编译它时 bad_any_cast 其中一个 std::any_cast s。

    我肯定我选对了。我加了一些垃圾 typeid(T).name() cout 以确保插入到 标准::任何 和我想要的类型。

    我试着写一个简单的程序来演示它,但是我不能复制它。

    值得一提的是: 我正在经过一包 标准::任何 (每个都包含不同的类型)并且只有一个有问题(它的 std::map<ENUM, int> ).

    当我切换到 boost::any (或者我用gcc构建我的应用程序)。

    我已经潜入 标准:任何演员 执行失败:

      template<typename _Tp>
        void* __any_caster(const any* __any)
        {
          if constexpr (is_copy_constructible_v<decay_t<_Tp>>)
          {
              if (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage)
              {
                  any::_Arg __arg;
                   __any->_M_manager(any::_Op_access, __any, &__arg);
                  return __arg._M_obj;
              }
            }
          return nullptr;
        }
    

    第二个if语句 (__any->_M_manager == &any::_Manager<decay_t<_Tp>>::_S_manage) 没有通过。

    在我看来 any::_Manager<decay_t<_Tp>>::_S_manage 同样的 _Tp (可能是由于我的应用程序由几个模块组成)但是我不能在一个更简单的例子中重现它。

    你们有什么建议或提示我怎么处理吗?

    编辑

    在评论和答案的启发下,我创建了一个例子,在这里我搞砸了默认可见性(这也是我在应用程序中做的事情),这似乎是问题的根源。

    文件夹:

    库cpp

    #include <any>
    #include <map>
    
    enum class D
    {
        a,
        b,
        c,
        d,
        e,
    };
    
    int read(const std::any& a)
    {
        auto map = std::any_cast<std::map<D, int>>(a);
        return map.begin()->second;
    }
    
    std::any create()
    {
        std::map<D, int> b = { {D::c, 5} };
    
        std::any a(b);
    
        return a;
    }
    

    lib2.cpp文件

    #include <any>
    #include <map>
    
    std::any create();
    int read(const std::any& a);
    
    __attribute__ ((visibility("default"))) std::any build_bar2()
    {
        return create();
    }
    
    __attribute__ ((visibility("default"))) int read_foo2(const std::any& a)
    {
        return read(a);
    }
    

    伦敦银行同业拆借利率

    #include <any>
    #include <map>
    
    int read(const std::any &);
    std::any create();
    
    __attribute__ ((visibility("default"))) int read_foo3(const std::any& a)
    {
        return read(a);
    }
    
    __attribute__ ((visibility("default"))) std::any build_bar3()
    {
        return create();
    }
    

    主.cpp

    #include <any>
    
    int read_foo2(const std::any& a);
    std::any build_bar2();
    
    int read_foo3(const std::any& a);
    std::any build_bar3();
    
    
    int main()
    {
        const std::any& a = build_bar3();
        int av = read_foo2(a);
    
        const std::any& b = build_bar2();
        int bv = read_foo3(a);
    
        return av == bv? 1: 0;
    }
    

    生成文件

    CPP=clang++
    
    all: main
    
    lib.o: lib.cpp
        $(CPP) -std=c++17 -fvisibility=hidden -g -O0 -fPIC -c lib.cpp -o lib.o
    
    lib2.so: lib2.cpp lib.o
        $(CPP) -std=c++17 -fvisibility=hidden -g -O0 -fPIC -shared lib2.cpp lib.o -o lib2.so
    
    lib3.so: lib3.cpp lib.o
        $(CPP) -std=c++17 -fvisibility=hidden -g -O0 -fPIC -shared lib3.cpp lib.o -o lib3.so
    
    
    main: main.cpp lib3.so lib2.so
        $(CPP) -std=c++17 -fvisibility=hidden -g -O0 main.cpp ./lib2.so ./lib3.so -o main
    
    clean:
        rm -f ./lib.o ./lib2.so ./lib3.so ./main
    

    所以我有两个共享库,它们链接公共静态库 标准::任何 创造和铸造。什么时候? 标准::任何 是在一个静态库中创建的,在另一个库中生成的,我得到一个异常。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Zan Lynx    6 年前

    如果您在Linux或OSX上使用UNIX,则C++类型ID由指向类型信息的指针来处理,而不是名称字符串匹配。

    这意味着,如果共享库或静态库具有“相同”类型,但它们有自己的单独副本,则类型信息将不匹配。

    这可能是你的情况,也可能不是。

    我相信你必须定义你的类型 any 在公共共享库中,以默认可见性声明。这将使所有其他共享库使用该副本,而不是从其静态库中隐藏副本。