clang vs gcc运行时差异:c ++类模板内置w clang崩溃没有复制构造函数,内置w gcc崩溃与复制构造函数

时间:2015-11-21 17:04:58

标签: c++ templates gcc clang copy-constructor

使用clang(但不是gcc)构建时,以下代码会在运行时崩溃,除非我为TableTypeCarrier模板类包含了一个复制构造函数吗?如果我包含该复制构造函数,为什么在使用gcc构建时遇到相同的运行时崩溃?

我定义了以下c ++类:

class TableTypeCarrierBase {};

template<class T>
class TableTypeCarrier: public TableTypeCarrierBase {
public:
    TableTypeCarrier(const T * const p) : m_p(p) {}

#ifdef __clang__
    TableTypeCarrier(const TableTypeCarrier<T>& o) : m_p(o.m_p) {}
#endif

    const T * Get() const
    {
      return m_p;
    }

private:
    const T * const m_p;
};

struct PsiTable {
    PsiTable() : m_priv(NULL) { }

    template<typename T> void Set(const TableTypeCarrier<T> inT)
    {
      m_priv = &inT;
    }

    template<typename T> const T * Get() const
    {
      return (!m_priv) ? NULL : ((TableTypeCarrier<T>*)m_priv)->Get(); 
    }

private:
    const TableTypeCarrierBase *m_priv;
};

您会注意到TableTypeCarrier类模板的复制构造函数被条件化为仅由clang构建,而不是由gcc构建。

在最初编写此代码时(没有上述条件化复制构造函数),我只使用gcc来构建和测试它。当我尝试使用clang构建它时,构建将始终成功,但是在操作这些类的对象时会出现运行时崩溃。

我花了几个月调试这个。我并没有完全回想起导致我尝试将复制构造函数添加到TableTypeCarrier模板类的路径,但实际上这解决了使用clang构建的二进制文件的问题。不幸的是,简单地声明这个拷贝构造函数似乎导致了与最初描述的相同的问题,但仅在使用gcc构建时。

当然,我添加了预编译器指令,只有在使用clang构建时才能复制构造函数。

此修复程序对我有用,但我想了解原因。

如果你需要上下文来完全理解这个问题,这里有一个标题的链接,当这个确切的代码仍然存在时,它在历史的某个时刻在整个项目中定义这些类:

https://github.com/mkrufky/libdvbtee/blob/v0.4.0/libdvbtee/decode/table/table.h

我已经重构了代码并完全删除了TableTypeCarrierBase类和TableTypeCarrier模板类,因为这些是不必要的代理。尽管删除了这段代码,我仍然想要理解为什么使用gcc构建的clang vs二进制文件构建的二进制文件在TableTypeCarrier具有(或缺少)复制构造函数时表现不同。

为什么clang-built二进制文件需要这个复制构造函数?如果我包含它,为什么gcc构建的二进制文件会崩溃?

1 个答案:

答案 0 :(得分:2)

我在这里看到一个问题:

template<typename T> void Set(const TableTypeCarrier<T> inT)
{
  m_priv = &inT;
}

您正在按值传递参数(并因此复制它),但随后您将获取它的地址并将其分配给成员变量。当函数结束时,你获取地址的对象消失,留下一个悬空指针。

处于适当高警告级别的编译器应该标记这一点。