Exc 访问错误
Posted
技术标签:
【中文标题】Exc 访问错误【英文标题】:Exc access error 【发布时间】:2013-08-04 22:24:24 【问题描述】:C++ 新手,返回向量时遇到问题。我放了一个断点,数组是正确的(填充了我期望从查询中得到的所有对象)。但是当它返回时,我得到一个错误: EXC_BAD_ACCESS 在线 m_pComponentContainer->removeAll(); 来自 CCNode.cpp
这很奇怪,因为这是一个基类(不从任何类型的 CC 对象继承)虽然我广泛使用 Cocos2dx 框架,但它不包含在此类中。
我很确定这是因为某些东西正在被释放。但是,就像我说的,我对 C++ 很陌生,并且不确定问题出在哪里。在我不得不开始担心内存管理之前,我希望能在开发中走得更远一些。
int numberOfCards = DatabaseHelper::getNumberOfCards();
//cant be zero
assert(numberOfCards);
std::vector<CardSlot> returnArray(numberOfCards);
sqlite3_stmt * statement;
if (sqlite3_open(this->dbpath.c_str(),&this->cardWarsDB) == SQLITE_OK)
const char* query_stmt = "select ID, HP, MP, AbilityText from Cards WHERE ID IN (SELECT DISTINCT cardsID FROM Deck WHERE name = 'All')";
if (sqlite3_prepare_v2(this->cardWarsDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
while (sqlite3_step(statement) == SQLITE_ROW)
CardSlot *aCard;
const char* cardID = (const char*)sqlite3_column_text(statement, 0);
const char* cardHP = (const char*)sqlite3_column_text(statement, 1);
const char* cardMP = (const char*)sqlite3_column_text(statement, 2);
const char* cardAbility = (const char*)sqlite3_column_text(statement, 3);
if (cardID != NULL)
std::string imageName = ".png";
imageName = cardID + imageName;
aCard = (CardSlot *)CardSlot::spriteWithFile(imageName.c_str());
if (cardID != NULL)
aCard->cardID = std::string(cardID);
cocos2d::CCLog("DB returned results, cardID: %s",aCard->cardID.c_str());
if (cardHP != NULL)
aCard->cardHP = std::string(cardHP);
cocos2d::CCLog("DB returned results, cardHP: %s",aCard->cardHP.c_str());
if (cardMP != NULL)
aCard->cardMP = std::string(cardMP);
cocos2d::CCLog("DB returned results, cardMP: %s",aCard->cardMP.c_str());
if (cardAbility != NULL)
aCard->cardAbility = std::string(cardAbility);
cocos2d::CCLog("DB returned results, cardAbility: %s",aCard->cardAbility.c_str());
numberOfCards--;
returnArray[numberOfCards] = *aCard;
sqlite3_finalize(statement);
sqlite3_close(this->cardWarsDB);
return returnArray;
这是堆栈跟踪的屏幕截图。我只是看着它,似乎是 CardSlot 对象是罪魁祸首。 但是还是不知道如何“保留”它们,不过我会看一些 Cocos 文档。
NOTE1
【问题讨论】:
也许 sqlite_step 迭代次数超过 numberOfCards 次?你可以在那里做一个简单的检查,例如:if(numberOfCards-- == 0) reportError();
不:(它运行了五次。它达到零,但这是设计使然(对于 0 索引)
好的,但是您是在增量之前还是之后检查值?如果条件(numberOfCards-- == 0)
为真,那么您遇到了访问冲突。
您的堆栈跟踪显示了CardSlot
的析构函数。这是需要您注意的,还有复制构造函数和赋值运算符。
这一行:aCard = * CardSlot::spriteWithFile(imageName.c_str());
,看起来非常非常可疑。
【参考方案1】:
您的CardSlot
似乎无法安全复制。你至少在两个地方复制CardSlot
s:
aCard = * CardSlot::spriteWithFile(imageName.c_str());
(假设spriteWithFile
返回CardSlot *
,也是内存泄漏;“临时”没有被破坏)
returnArray[numberOfCards] = aCard;
据我所知,您可能在CardSlot
中保留了一个CCSprite
指针,并在您的CardSlot
析构函数中销毁它(使用delete
)。但是,由于副本的原因,该指针会被多次销毁,从而导致崩溃。
您需要重新设计您的类,以便可以安全地复制它,或者重构您的代码以便不复制(例如,使用vector<shared_ptr<CardSlot> >
来保存指向实例的指针)。
【讨论】:
我一直在调查你所说的,几个问题。首选方法是什么?在我看来,指针向量很好,但我应该担心我的类不能被复制吗?我没有任何析构函数,尽管我认为 CCNode(CardSlot 的父级)确实如此,这就是所谓的。让我感到困惑的是,如果它仍然被向量引用,为什么它会被解构。我还让 aCard 成为一个指针而不是一个实例化的对象,它应该可以正确地消除泄漏(检查上面的编辑)? @owengerig:C++ 不做引用计数。CardSlot
的每个实例都是独立的:将CardSlot a,b; a = b;
复制 b
完全写入a
。
不,我知道 C++ 中没有引用计数器,但我使用的大部分术语来自 obj-c :(。如果我们重新审视“什么是首选方法”,在我看来,我不想创建副本,应该使用指针。【参考方案2】:
我已编辑代码以使用更多指针,而不是四处传递并用对象填充我的数组。然而,我认为有助于解决它的一件大事是使用cocos2d::CCArray
而不是std::vector.
我的大多数类都是 Cocos2d 类(CCSprites 和 CCLayers)的子类,因此使用它自己的数组数据类型是有意义的。
cocos2d::CCArray DatabaseHelper::getAllCards()
int numberOfCards = DatabaseHelper::getNumberOfCards();
//cant be zero
assert(numberOfCards);
cocos2d::CCArray returnArray(numberOfCards);
sqlite3_stmt * statement;
if (sqlite3_open(this->dbpath.c_str(),&this->cardWarsDB) == SQLITE_OK)
const char* query_stmt = "select ID, HP, MP, AbilityText from Cards WHERE ID IN (SELECT DISTINCT cardsID FROM Deck WHERE name = 'All')";
if (sqlite3_prepare_v2(this->cardWarsDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
while (sqlite3_step(statement) == SQLITE_ROW)
CardSlot* aCard;
const char* cardID = (const char*)sqlite3_column_text(statement, 0);
const char* cardHP = (const char*)sqlite3_column_text(statement, 1);
const char* cardMP = (const char*)sqlite3_column_text(statement, 2);
const char* cardAbility = (const char*)sqlite3_column_text(statement, 3);
if (cardID != NULL)
std::string imageName = ".png";
imageName = cardID + imageName;
aCard = CardSlot::spriteWithFile(imageName.c_str());
if (cardID != NULL)
aCard->cardID = std::string(cardID);
cocos2d::CCLog("DB returned results, cardID: %s",aCard->cardID.c_str());
if (cardHP != NULL)
aCard->cardHP = std::string(cardHP);
cocos2d::CCLog("DB returned results, cardHP: %s",aCard->cardHP.c_str());
if (cardMP != NULL)
aCard->cardMP = std::string(cardMP);
cocos2d::CCLog("DB returned results, cardMP: %s",aCard->cardMP.c_str());
if (cardAbility != NULL)
aCard->cardAbility = std::string(cardAbility);
cocos2d::CCLog("DB returned results, cardAbility: %s",aCard->cardAbility.c_str());
numberOfCards--;
returnArray.addObject(aCard);
sqlite3_finalize(statement);
sqlite3_close(this->cardWarsDB);
return returnArray;
//incase sql fails, close db and created a "FAILED" card
sqlite3_close(this->cardWarsDB);
cocos2d::CCLog("DB returned error: cant open char catagories file");
cocos2d::CCArray failedReturnArray(1);
CardSlot * aCard;
aCard->cardID = std::string("FAILED");
aCard->cardHP = std::string("FAILED");
aCard->cardMP = std::string("FAILED");
aCard->cardAbility = std::string("FAILED");
failedReturnArray.addObject(aCard);
return failedReturnArray;
如果有人关心这里是 CardSlot (不多,此时只构建了构造函数):
CardSlot * CardSlot::spriteWithFile(const char *pszFileName)
CCLOG("CardSlot::spriteWithFile");
CardSlot * aCard = new CardSlot();
if (aCard && aCard->initWithFile(pszFileName))
aCard->cardID = pszFileName;
aCard->scheduleUpdate();
aCard->autorelease();
return aCard;
CC_SAFE_DELETE(aCard);
return NULL;
我唯一关心的是我认为我的 CCArray 应该是一个指针。但是它现在可以工作,并且学习所有内存管理“交易技巧”会及时出现,我使用 C++ 的工作越多
感谢@nneonneo 的所有帮助我确信您的修复会奏效,我尝试了,但无论我做了什么都无法让矢量工作。我尽可能多地支持你,但实际上这是我实施的“答案”。
【讨论】:
【参考方案3】:returnArray
被声明为函数的局部变量,当函数返回时它会被释放。您需要将其声明为 static
或将声明移至函数外部。
【讨论】:
按值返回vector
对象是完全合法的。以上是关于Exc 访问错误的主要内容,如果未能解决你的问题,请参考以下文章
iphone sdk 值从给定 exc 错误访问的数组中删除
Swift 在访问 NSManagedObject 的属性时给出错误线程 1:EXC_BAD_ACCESS(code=1, address=0x0)