如何将std :: string解析为std :: string

JVA*_*pen 2 c++ string demangler c++11 libc++

我一直在使用一些demangling代码,以帮助进行一些调试,而无需使用动态强制转换编写数千行,或者必须实现返回类名的虚函数.

template <class CLASS>
std::string getClassName(CLASS &theObject)
{
    int status = 0;

    // Convert real name to readable string
    char *realName = abi::__cxa_demangle(typeid(theObject).name(), nullptr,
                                         nullptr, &status);
    ASSERT(status == 0); // Assert for success
    VERIFY(realName, return std::string());
    // Return as string + prevent memory leaks!
    const std::string result(realName);
    free(realName);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

这段代码背后的想法很简单,输出我们实际使用的类.虽然在切换到Ubuntu 14.04之后我无法再使用clang和c ++ - 11/c ++ - 14标准进行编译,所以我转而使用libc ++而不是libstdc ++.

在切换到libc ++之后,我注意到当我对'std :: string'进行demangle时它不再输出'std :: string',而是输出:

std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >
Run Code Online (Sandbox Code Playgroud)

当然这是正确的,因为std :: string是std :: basic_string的typedef.虽然我在libc ++中都可以看到libstdc ++,但是使用typedef以相同的方式定义.所以我真的不明白为什么这个demangling通过切换到libc ++而改变了.

有人知道为什么这是不同的如何获得'std :: string'如果CLASS将是'std :: string',而'myTemplate'当CLASS将是'myTemplate'?

Tnx提前!

JVApen

How*_*ant 7

libc ++用于inline namespaces对其ABI进行版本控制.它当前使用的内联命名空间是std::__1.这样做是为了让Apple可以同时发布gcc libstdc ++和libc ++.Dylib A可能链接到libstdc ++,而dylib B可能链接到libc ++,并且应用程序可能链接到两个dylib.当发生这种情况时,您不希望意外地将libstdc ++ std::string与libc ++混淆std::string.

它们具有相同的API,因此通过std::string穿过dylib边界很容易意外地做到.解决方案是告诉编译器以不同方式对它们进行修改,这正是内联命名空间所做的(并且是为其发明的).现在,如果它们在应用程序中意外混合,将导致链接时间错误,因为链接器会看到两种不同的类型,如其不同的错位名称所示.

demangler的工作就是简单地说实话:你喂它的符号的解码名称是什么.它工作得很好.

确实存在一种在libc ++中关闭ABI版本的方法.搜索<__ config>以获取_LIBCPP_BEGIN_NAMESPACE_STD_LIBCPP_END_NAMESPACE_STD.您可以看到某些平台如何定义此内容以打开内联命名空间,而有些平台则不会.这是一个非常大的锤子用于你的问题. 一切,如果你用这种方式改变的libc中的ABI ++,编译和对你的平台上的libc ++链接必须重建.

以下是我有时使用的问题的简单部分解决方案:

#include <iostream>
#include <type_traits>
#include <memory>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cxxabi.h>

namespace
{

inline
void
filter(std::string& r, const char* b)
{
    const char* e = b;
    for (; *e; ++e)
        ;
    const char* pb = "std::__1::";
    const int pl = std::strlen(pb);
    const char* pe = pb + pl;
    while (true)
    {
        const char* x = std::search(b, e, pb, pe);
        r.append(b, x);
        if (x == e)
            break;
        r += "std::";
        b = x + pl;
    }
}

}  // unnamed namespace

template <typename T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::unique_ptr<char, void(*)(void*)> own
           (
                __cxxabiv1::__cxa_demangle(typeid(TR).name(), nullptr,
                                           nullptr, nullptr),
                std::free
           );
    std::string r;
    if (own)
    {
        if (std::is_const<TR>::value)
            r += "const ";
        if (std::is_volatile<TR>::value)
            r += "volatile ";
        filter(r, own.get());
        if (std::is_lvalue_reference<T>::value)
            r += "&";
        else if (std::is_rvalue_reference<T>::value)
            r += "&&";
    }
    else
        r = typeid(TR).name();
    return r;
}
Run Code Online (Sandbox Code Playgroud)

这只是::__1在将错误的名称呈现给您之前过滤掉它.你也可以使用相同的技术,然后转化std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >std::string,如果你想.

安腾ABI只有对应的typedef这样的"压缩"了一把.它们是std::string,std::istream,std::ostreamstd::iostream.