[英]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.