调试版本和发布版本之间std::map行为的差异(Xcode 8.3,C+;+;11,Cocos2d-x)
在Cocos2d-x框架上,在Xcode 8.3.3、C++11中构建的调试版本之间出现了意外的行为差异。我正在使用emplace()方法填充一个std::map(_randomLetterChancesToAppear),该映射在调试中正确构建,但在发行版中似乎没有填充。当两个值预期相等时,此断言被触发:调试版本和发布版本之间std::map行为的差异(Xcode 8.3,C+;+;11,Cocos2d-x),xcode,c++11,stl,cocos2d-x,release,Xcode,C++11,Stl,Cocos2d X,Release,在Cocos2d-x框架上,在Xcode 8.3.3、C++11中构建的调试版本之间出现了意外的行为差异。我正在使用emplace()方法填充一个std::map(_randomLetterChancesToAppear),该映射在调试中正确构建,但在发行版中似乎没有填充。当两个值预期相等时,此断言被触发: CC_ASSERT(outCellDetail._randomLetterChancesToAppear.size() == alphabetCount); 当assert在发布版本中跳闸
CC_ASSERT(outCellDetail._randomLetterChancesToAppear.size() == alphabetCount);
当assert在发布版本中跳闸时,randomLetterChancesToAppear似乎不包含任何数据。(为了测试这一点,如果相关的话,我创建了一个复制的Xcode方案到我的默认移动方案,并将运行构建配置更改为release,以允许我测试连接了IDE的发布构建。)
以下是令人不快的方法:
void GameDataController::PopulateIndividualCellChancesToAppear(CellDetail &outCellDetail, const rapidjson::Value &cellDetailObject, const GameDetail& constGameDetail) const
{
cocostudio::DictionaryHelper* dicTool = cocostudio::DictionaryHelper::getInstance();
CC_ASSERT(dicTool->checkObjectExist_json(cellDetailObject, "LetterChancesToAppear"));
CCASSERT(constGameDetail._alphabet.length() > 0, "Zero-length alphabet!");
const rapidjson::Value& letterChancesObject = dicTool->getSubDictionary_json(cellDetailObject, "LetterChancesToAppear");
// iterate through each letter in this game detail's alphabet
const int alphabetCount = static_cast<int>(constGameDetail._alphabet.length());
std::vector<char> lettersNeedingChances;
for (int i = 0; i < alphabetCount; ++i)
{
// if a given alphabet letter has a chance to appear, save it.
const char alphabetChar = constGameDetail._alphabet.at(i);
char letterChanceKey[1];
sprintf(letterChanceKey, "%c", alphabetChar);
if (dicTool->checkObjectExist_json(letterChancesObject, letterChanceKey))
{
const float ChanceToAppear = dicTool->getFloatValue_json(letterChancesObject, letterChanceKey);
CC_ASSERT(!std::isnan(ChanceToAppear));
CC_ASSERT(ChanceToAppear >= 0.0f);
outCellDetail._randomLetterChancesToAppear.emplace(alphabetChar, !std::isnan(ChanceToAppear) ? ChanceToAppear : 0.0f);
}
else
{
// ... otherwise, store the letter in a list of letters without assigned chances.
lettersNeedingChances.push_back(alphabetChar);
}
}
// fill in missing chances to appear.
if (lettersNeedingChances.size() > 0)
{
float defaultRemainingChance = 1.0f / static_cast<float>(alphabetCount);
CC_ASSERT(!std::isnan(defaultRemainingChance));
CC_ASSERT(defaultRemainingChance > FLT_EPSILON);
for (const char remainingChar : lettersNeedingChances)
{
CCLOG("Character %c doesn't have a chance to appear specified. Using default %f", remainingChar, defaultRemainingChance);
outCellDetail._randomLetterChancesToAppear.emplace(remainingChar, defaultRemainingChance);
}
}
// vvvv THIS ASSERT IS FAILING IN RELEASE, BUT NOT IN DEBUG BUILD CONFIGURATIONS. vvvvv
CC_ASSERT(outCellDetail._randomLetterChancesToAppear.size() == alphabetCount);
// normalize chances to appear.
float chanceTotal = 0.0f;
for(auto iterator = outCellDetail._randomLetterChancesToAppear.begin();
iterator != outCellDetail._randomLetterChancesToAppear.end();
iterator++)
{
chanceTotal += iterator->second;
}
if (std::abs(chanceTotal - 1.0f) > FLT_EPSILON)
{
float adjustmentFactor = 1.0f / chanceTotal;
float adjustedChanceTotal = 0.0f;
for(auto iterator = outCellDetail._randomLetterChancesToAppear.begin();
iterator != outCellDetail._randomLetterChancesToAppear.end();
iterator++)
{
iterator->second = iterator->second * adjustmentFactor;
adjustedChanceTotal += iterator->second;
}
CCASSERT(std::abs(adjustedChanceTotal - 1.0f) <= FLT_EPSILON, "adjustedChanceTotal != 1.0f");
}
}
void GameDataController::PopulateIndividualCellChancesToAppear(CellDetail&outCellDetail,const rapidjson::Value&cellDetailObject,const GameDetail&const GameDetail)const
{
cocostudio::DictionaryHelper*dicTool=cocostudio::DictionaryHelper::getInstance();
CC_ASSERT(dicTool->checkObjectExist_json(cellDetailObject,“lettchancestoappear”);
CCASSERT(constGameDetail._alphabet.length()>0,“零长度字母表!”);
const rapidjson::Value&letterChancesObject=dicTool->getSubDictionary_json(cellDetailObject,“LetterChancesToAppear”);
//在游戏细节的字母表中重复每个字母
const int alphabetCount=static_cast(constGameDetail._alphabet.length());
std::矢量字母增量;
对于(int i=0;icheckObjectExist_json(lettchanceobject,lettchancekey))
{
const float ChanceToAppear=dicTool->getFloatValue_json(lettchanceobject,lettchancekey);
CC_ASSERT(!std::isnan(ChanceToAppear));
CC_断言(偶然出现>=0.0f);
outCellDetail._randomLetterChancesToAppear.emplace(alphabetChar,!std::isnan(ChanceToAppear)?ChanceToAppear:0.0f);
}
其他的
{
//…否则,请将该字母存储在没有指定机会的字母列表中。
字母变长。推回(alphabetChar);
}
}
//填补错过的出现机会。
如果(lettersNeedingChances.size()>0)
{
float defaultRemainingChance=1.0f/静态施法(字母计数);
CC_ASSERT(!std::isnan(defaultRemainingChance));
CC_ASSERT(defaultRemainingChance>FLT_EPSILON);
for(常量字符剩余字符:字母更改)
{
CCLOG(“字符%c没有机会出现指定的字符。使用默认的%f”,remainingChar,defaultRemainingChance);
outCellDetail.\u随机字母机会出现在安放位置(保留字符,默认保留机会);
}
}
//此断言在版本中失败,但在调试生成配置中失败。vvv
CC_ASSERT(outCellDetail._randomLetterChancesToAppear.size()=alphabetCount);
//使出现的机会正常化。
浮动通道总数=0.0f;
对于(自动迭代器=outCellDetail._randomLetterChancesToAppear.begin();
迭代器!=outCellDetail.\u randomLetterChancesToAppear.end();
迭代器++)
{
chanceTotal+=迭代器->秒;
}
如果(标准::abs(信道总数-1.0f)>FLT_ε)
{
浮动调整系数=1.0f/通道总数;
浮动调整通道总=0.0f;
对于(自动迭代器=outCellDetail._randomLetterChancesToAppear.begin();
迭代器!=outCellDetail.\u randomLetterChancesToAppear.end();
迭代器++)
{
迭代器->第二个=迭代器->第二个*调整因子;
调整后的信道总数+=迭代器->秒;
}
CCASSERT(std::abs(adjusted chancetotal-1.0f)答案归谁
char letterChanceKey[1];
sprintf(letterChanceKey, "%c", alphabetChar);
没有为终止NUL留出足够的空间,导致缓冲区溢出。增加缓冲区大小修复了该问题
谢谢你,Igor!他的行为可能是未定义的,即.UB。你应该尝试使用valgrind之类的工具,Xcode可能也有类似的功能。这可以告诉你:如果你正在使用未初始化的内存或写入未分配的内存。在寻找这类错误时,还有许多其他工具可供使用。charletterChanceKey[1];sprintf(letterChanceKey,“%c”,alphabetChar);
这通过缓冲区溢出的方式表现出未定义的行为。letterChanceKey
没有空间容纳终止NUL。非常感谢Igor!增加缓冲区大小似乎解决了问题。