[英]Why do I get an “Access violation” in this C++ code
我有以下三个课程:
class BeliefRoot
{
std::string m_Name;
BeliefRoot(std::string Name) : m_Name(Name)
{ }
};
template <class factType>
class Belief : public BeliefRoot
{
factType m_Fact;
explicit Belief(std::string UniqueName, factType InitialFact = NULL)
: BeliefRoot(UniqueName), m_Fact(InitialFact)
{ }
};
template <class factType>
class BeliefSet : public Belief<factType>
{
std::list<factType> m_Facts;
explicit BeliefSet(std::string UniqueName) : Belief(UniqueName)
{ }
};
现在我想两次实例化BeliefSet
类:
BeliefSet<float> bSetFloat("SetFloat");
BeliefSet<std::string> bSetString("SetString");
第一个很好,但是在第二个调用中,出现以下错误:
0xC0000005:访问冲突读取位置0x0000000000000000。
有人可以解释为什么会发生这种情况吗,但std::string
与std::string
?
factType是字符串。 所以这相当于
string m_Fact = NULL;
factType InitialFact = NULL
,其中factType = std::string
将尝试使用单个参数const char*
构造const char*
构造std::string
。 从nullptr
构造std::string
会导致此崩溃。
对于具有泛型(取决于模板参数)类型的默认参数,您不需要= 0
(这是使用NULL
宏得到的)。 它将为std::string
选择一个转换构造函数,而不是默认构造函数,并且该转换构造函数禁止传递空指针值。 崩溃是违反该先决条件的结果。
您也不需要默认初始化,这将使基元完全不进行初始化。 C ++的“值初始化”概念在这里可以为您提供良好的服务...具有非平凡构造的类型的默认构造,否则为零初始化。
好的选择是从值初始化的默认值进行复制初始化,或者使用空列表进行非常方便的列表初始化,这在语法上非常短,并且也适用于聚合(因为C ++ 11为标量类型提供了值初始化,在此之前它仅对聚合有用):
/* C++03 value-initialization */
explicit Belief(std::string UniqueName, factType InitialFact = factType())
/* list-initialization, since C++11 this also works great for scalars */
explicit Belief(std::string UniqueName, factType InitialFact = {})
正如其他人指出的那样,您的问题是=NULL
; 下面我将详细描述它,并描述如何修复您的代码。
explicit BeliefSet(std::string UniqueName) :
Belief<factType>(UniqueName)
{}
使用factType
= std::string
,调用:
explicit Belief(
std::string UniqueName,
std::string InitialFact = NULL
) :
BeliefRoot(UniqueName),
m_Fact(InitialFact)
{}
和
std::string InitialFact = NULL
是非法的。 替换为={}
,为您提供:
class BeliefRoot
{
std::string m_Name;
BeliefRoot(std::string Name):
m_Name(Name)
{}
};
template <class factType>
class Belief : public BeliefRoot
{
factType m_Fact;
explicit Belief(
std::string UniqueName,
factType InitialFact = {}
):
BeliefRoot(UniqueName),
m_Fact(InitialFact)
{}
};
template <class factType>
class BeliefSet : public Belief<factType>
{
std::list<factType> m_Facts;
explicit BeliefSet(std::string UniqueName):
Belief(UniqueName)
{}
};
并且您的代码应该可以正常工作。
让我们看看BeliefSet<std::string>
在编译时解析为什么:
//We're appending __string to indicate how the type will (roughly) be represented at compiletime.
class Belief__string : public BeliefRoot
{
std::string m_Fact;
explicit Belief(std::string UniqueName, std::string InitialFact = 0)
: BeliefRoot(UniqueName), m_Fact(InitialFact)
{ }
};
class BeliefSet__string : public Belief__string
{
std::list<std::string> m_Facts;
explicit BeliefSet(std::string UniqueName) : Belief(UniqueName)
{ }
};
因此,立即可疑的代码位于中间类中: std::string InitialFact = 0
。 它的格式不正确,但是几乎可以肯定发生的是字符串正在尝试为其分配空指针。 字符串可以接收const char *
类型进行构造,因此它可能试图从此null指针读取,并且由于取消引用null
而立即失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.