使用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构建的二进制文件会崩溃?
答案 0 :(得分:2)
我在这里看到一个问题:
template<typename T> void Set(const TableTypeCarrier<T> inT)
{
m_priv = &inT;
}
您正在按值传递参数(并因此复制它),但随后您将获取它的地址并将其分配给成员变量。当函数结束时,你获取地址的对象消失,留下一个悬空指针。
处于适当高警告级别的编译器应该标记这一点。