0

对 C++ 非常陌生,并且在返回向量时遇到问题。我放了一个断点,数组是正确的(填充了我期望从查询中得到的所有对象)。但是当它返回时我得到一个错误: EXC_BAD_ACCESS on line 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 文档。

在此处输入图像描述

注1

4

3 回答 3

1

看来您CardSlot的复制不安全。CardSlot您至少在两个地方复制s:

  • aCard = * CardSlot::spriteWithFile(imageName.c_str());spriteWithFile(假设返回也是内存泄漏CardSlot *;“临时”没有被破坏)
  • returnArray[numberOfCards] = aCard;

据我所知,您可能在析构函数CCSprite中保留了一个指针CardSlot并销毁它(使用deleteCardSlot。但是,由于副本,此指针会被多次销毁,从而导致您的崩溃。

您需要重新设计您的类以便可以安全地复制它,或者重构您的代码以便您不进行复制(例如,通过使用 avector<shared_ptr<CardSlot> >来保存指向实例的指针)。

于 2013-08-05T08:01:02.643 回答
0

我已经编辑了代码以使用更多指针,而不是传递并用对象填充我的数组。然而,我认为帮助修复它的一件大事是使用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 提供的所有帮助我确信您的修复会奏效,我尝试了,但无论我做了什么,都无法让向量工作。我尽可能多地支持你,但实际上这是我实施的“答案”。

于 2013-08-07T16:59:27.873 回答
-1

被声明为函数的returnArray本地,它将在函数返回时被释放。您需要将其声明为static或将声明移至函数外部。

于 2013-08-05T07:49:25.550 回答