[英]Why do I get an “Access violation” in this C++ code
I have the following three classes: 我有以下三个课程:
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)
{ }
};
Now I want to instantiate the class BeliefSet
two times: 现在我想两次实例化
BeliefSet
类:
BeliefSet<float> bSetFloat("SetFloat");
BeliefSet<std::string> bSetString("SetString");
The first is fine, but at the second call I get the following error: 第一个很好,但是在第二个调用中,出现以下错误:
0xC0000005: Access violation reading location 0x0000000000000000. 0xC0000005:访问冲突读取位置0x0000000000000000。
Can somebody explain why this happens, but only if used with std::string
? 有人可以解释为什么会发生这种情况吗,但
std::string
与std::string
?
factType is string. factType是字符串。 So it is equivalent to
所以这相当于
string m_Fact = NULL;
factType InitialFact = NULL
where factType = std::string
will attempt to construct a std::string
using the single argument const char*
constructor. factType InitialFact = NULL
,其中factType = std::string
将尝试使用单个参数const char*
构造const char*
构造std::string
。 Constructing a std::string
from a nullptr
will cause this crash. 从
nullptr
构造std::string
会导致此崩溃。
For a default parameter having generic (dependent on template parameters) type, you don't want = 0
(which is what you get with the NULL
macro). 对于具有泛型(取决于模板参数)类型的默认参数,您不需要
= 0
(这是使用NULL
宏得到的)。 It'll select a converting constructor for std::string
instead of the default constructor, and that converting constructor forbids passing a null pointer value. 它将为
std::string
选择一个转换构造函数,而不是默认构造函数,并且该转换构造函数禁止传递空指针值。 The crash is a consequence of violating that precondition. 崩溃是违反该先决条件的结果。
You also don't want default initialization, which leaves primitives with no initialization at all. 您也不需要默认初始化,这将使基元完全不进行初始化。 The C++ concept of "value-initialization" serves you well here... default construction for types with non-trivial construction, and zero initialization otherwise.
C ++的“值初始化”概念在这里可以为您提供良好的服务...具有非平凡构造的类型的默认构造,否则为零初始化。
Good options then are copy-initialization from a value-initialized default, or the very handy list-initialization with an empty list, which is very short syntactically and also works for aggregates (since C++11 it gives value-initialization for scalar types, before that it was only useful for aggregates): 好的选择是从值初始化的默认值进行复制初始化,或者使用空列表进行非常方便的列表初始化,这在语法上非常短,并且也适用于聚合(因为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 = {})
As others have noted, your problem is the =NULL
; 正如其他人指出的那样,您的问题是
=NULL
; below I describe it in detail, and also describe how to fix your code. 下面我将详细描述它,并描述如何修复您的代码。
explicit BeliefSet(std::string UniqueName) :
Belief<factType>(UniqueName)
{}
with factType
= std::string
, calls: 使用
factType
= std::string
,调用:
explicit Belief(
std::string UniqueName,
std::string InitialFact = NULL
) :
BeliefRoot(UniqueName),
m_Fact(InitialFact)
{}
and 和
std::string InitialFact = NULL
is illegal. 是非法的。 Replace with
={}
, giving you: 替换为
={}
,为您提供:
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)
{}
};
and your code should work. 并且您的代码应该可以正常工作。
Let's take a look at what BeliefSet<std::string>
resolves to at compiletime: 让我们看看
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)
{ }
};
So the immediately suspicious code is in the intermediate class: std::string InitialFact = 0
. 因此,立即可疑的代码位于中间类中:
std::string InitialFact = 0
。 This is poorly formed, but what's almost certainly happening is the string is trying to have a null pointer assigned to it. 它的格式不正确,但是几乎可以肯定发生的是字符串正在尝试为其分配空指针。 Strings can receive
const char *
types for construction, so it may be trying to read from this null pointer, and immediately failing due to dereferencing null
. 字符串可以接收
const char *
类型进行构造,因此它可能试图从此null指针读取,并且由于取消引用null
而立即失败。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.