C++ clang与gcc运行时差异:c++;类模板生成时没有复制构造函数,但发生了clang崩溃;生成时有gcc崩溃,但有复制构造函数

C++ clang与gcc运行时差异:c++;类模板生成时没有复制构造函数,但发生了clang崩溃;生成时有gcc崩溃,但有复制构造函数,c++,templates,gcc,clang,copy-constructor,C++,Templates,Gcc,Clang,Copy Constructor,除非我为TableTypeCarriertemplate类包含一个复制构造函数,否则在使用clang(但不是gcc)构建时,以下代码在运行时会崩溃吗?如果我包含了复制构造函数,为什么在使用gcc构建时会遇到相同的运行时崩溃 我定义了以下C++类: class TableTypeCarrierBase {}; template<class T> class TableTypeCarrier: public TableTypeCarrierBase { public: Tabl

除非我为
TableTypeCarrier
template类包含一个复制构造函数,否则在使用clang(但不是gcc)构建时,以下代码在运行时会崩溃吗?如果我包含了复制构造函数,为什么在使用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;
};
类TableTypeCarrierBase{};
模板
类TableTypeCarrier:公共TableTypeCarrier数据库{
公众:
TableTypeCarrier(常数T*常数p):m_p(p){}
#如果有声音__
TableTypeCarrier(const TableTypeCarrier&o):m_p(o.m_p){}
#恩迪夫
常量T*Get()常量
{
返回m_p;
}
私人:
常数T*常数mp;
};
结构PsiTable{
PsiTable():m_priv(NULL){}
模板无效集(const TableTypeCarrier inT)
{
m_priv=&inT;
}
模板常量T*Get()常量
{
返回(!m_priv)?NULL:((TableTypeCarrier*)m_priv)->Get();
}
私人:
const TableTypeCarrierBase*m_priv;
};
您会注意到,
TableTypeCarrier
类模板的复制构造函数被条件化为仅由clang而不是gcc构建

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

我花了几个月调试这个。我记不清是什么原因导致我尝试向
TableTypeCarrier
模板类添加副本构造函数的,但这确实解决了使用clang构建二进制文件的问题。不幸的是,仅仅声明这个副本构造函数似乎会导致与最初描述的相同的问题,但只有在使用gcc构建时才会出现

当然,我添加了预编译器指令,以仅在使用clang构建时对复制构造函数进行条件化

这个方法对我很有效,但我想知道为什么

如果您需要上下文来完全理解问题,这里有一个指向在完整项目中定义这些类的标题的链接,该标题在历史记录中的某一点上定义了这些类,而此时仍然存在这段代码:

此后,我对代码进行了重构,删除了
TableTypeCarrierBase
类和
TableTypeCarrier
模板类,因为它们是不必要的代理。尽管删除了这段代码,但我仍然想理解,当
TableTypeCarrier
具有(或缺少)一个拷贝构造函数时,为什么使用clang构建的二进制文件与使用gcc构建的二进制文件表现不同

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

我发现了一个问题:

template<typename T> void Set(const TableTypeCarrier<T> inT)
{
  m_priv = &inT;
}
模板无效集(const TableTypeCarrier inT)
{
m_priv=&inT;
}
您正在按值传递参数(并因此制作参数的副本),但随后将获取参数的地址并将其分配给成员变量。当函数结束时,获取其地址的对象消失,留下一个悬空指针


处于适当高警告级别的编译器应该对此进行标记。

您确定代码中其他地方没有未定义的行为吗?我认为除了你之外,没有人可以这样说,除非你提供一个我不确定我还能提供什么(除了github链接)来让我的示例更完整:-/我认为,任何使用这些类的其他代码都太多,无法粘贴到这个问题帖子中。你不应该只提供一些额外的代码。你应该做一个MCVE,这意味着删除额外的代码,除非你绝对确定不能删除更多的代码。谢谢你的反馈。这将有助于我今后提出更好的问题。然而,有人已经发现了一个可能导致我的问题答案的代码问题,所以我希望这个问题不会结束。这是一个很好的发现。我不确定这是否解释了gcc和clang之间的行为差异,但我肯定会马上修复它。您的TableStore::add函数看起来也很可疑。但我看不到完整的实现。也许你在中查找代码?我说不出来。但这取决于在后续函数调用中如何处理在add函数中创建的局部变量。请记住,当add函数结束时,这些局部变量将消失。PsiTable对象将传递到LinkedTable的构造函数中。传入数据(在该PsiTable内)的所有工作都在此构造函数中处理,并且PsiTable(及其私有内部指针)在LinkedTable构造函数外不再使用。此LinkedTable构造函数复制它所需的数据,并且不再接触PsiTable源。