gpt4 book ai didi

c++ - 我的调试器说我有一个段错误但不能告诉我在哪里,发生在非常特殊的情况下

转载 作者:行者123 更新时间:2023-11-30 04:49:27 26 4
gpt4 key购买 nike

我的调试器 (gdb) 说我有一个段错误,但不能告诉我它在哪里,说 ?? () 为函数。

我在一个非常特殊的情况下开始出现错误,我点击了一个武器类型的项目,然后点击了另一个可用的项目,但我的程序出现了段错误。我从我的代码中删除了大部分指针,因为起初我认为这是问题所在,但它并没有改变任何东西。我无法在线找到类似的错误,调试也不是很有帮助,因为它无法告诉我错误的确切来源。

相关播放器.h

class Player{
private:
int HP; //player's Health Points
int SP; //player's Special Points
int maxHP; //maximum value for the player's health points
int maxSP; //maximum value for the player's special points
uint32_t money; //how much money the player has

float speed; //speed the player will move at (pixels per frame)

bool menuOpen; //boolean which is true when the inventory Menu is open

sf::Vector2f pos; //player's position

//tests if the player is colliding with any items
//in the room, accepts the memory address of the room
bool checkForItems(Room* r);

std::vector<int> ItemInventory; //the player's inventory of items.
std::vector<TextButton> itemButtons; //vector of TextButtons that correspond with each unique item in the player's inventory
std::map<std::string, int> ItemsList; //map that stores each unique item's name and it's quantity

Control openMenu; //control to open the menu

void ItemAttributes(int id); //makes the items do something depending on what was passed
bool removeItem(int id); //removes an item from the player's inventory
void useItem(Item it); //takes an Item* and passes it's ID to ItemAttributes
void updateButtons(); //updates the buttons based on the player's inventory

Item* EquipedWeapon; //stores the player's currently equipped weapon

//enum to store the player's direction for rotations
enum direction {
up,
down,
left,
right
} currentDirection;

void setRotation();
public:
//constructor for the player, initializes maxHP, maxSP, and their position:
Player(int maxhp, int maxsp, sf::Vector2f position);

//getters:
int ItemButtonsTextSearchC(const std::wstring& text); //returns the index in itemButtons for a TextButton which *contains* the text parameter
int ItemButtonsTextSearch(const std::wstring& text); //returns the index in itemButtons for a TextButton which equals the text parameter

//setters:
void setMoney(int amount); //sets the money variable
void setHP(int hp); //sets the HP variable
void setSP(int sp); //sets the SP variable

void menu(); //inventory menu, handles all things related to the player's inventory
void draw(); //draws the player to the screen
};

Player.cpp 中导致问题的方法:

void Player::menu(){
//iterate through all the items listed in itemsList:
for(auto& p : ItemsList){
//get a pointer to the item by it's name:
Item item = *Materials::getItemFromName(p.first);

//convert the item's name to a wstring for easier use in parameters:
std::wstring wItemName = std::wstring(p.first.begin(), p.first.end());

//get the index of the item's corresponding button
//by searching the itemButtons vector for a button
//whose text matches this item's name:
int bIndex = ItemButtonsTextSearch(wItemName);

if(bIndex != -1){
//store the button's position:
sf::Vector2f buttonPosition = itemButtons.at(bIndex).getPosition();

//default the Y values to 150, we need a separate Y for each one
//because there are 4 columns of buttons for each type of item
float weaponY = 150, usableY = 150, collectibleY = 150, moneyY = 150;

//switch statement to determine the position of the button:
switch(item.getType()){
case Item::Weapon:
buttonPosition.x = 100;
buttonPosition.y = weaponY;

//increment by 20 to give space between buttons:
weaponY += 20.0f;
break;
case Item::Usable:
buttonPosition.x = 375;
buttonPosition.y = usableY;

//increment by 20 to give space between buttons:
usableY += 20.0f;
break;
case Item::Collectible:
buttonPosition.x = 650;
buttonPosition.y = collectibleY;

//increment by 20 to give space between buttons:
collectibleY += 20.0f;
break;
case Item::Money:
buttonPosition.x = 925;
buttonPosition.y = moneyY;

//increment by 20 to give space between buttons:
moneyY += 20.0f;
break;
}

//set the button's position now that it's X has been determined:
itemButtons.at(bIndex).setPosition(buttonPosition);

/*
* below we will set the button's text to represent
* it's corresponding item's name as well as it's
* quantity then draw the button to the screen so
* that the client can see how many of each item
* they have, but then we change it back so that it
* doesn't break any comparisons with the button's
* Text (ItemButtonsTextSearch for example):
*/

//text representing item's quantity to append to the end of the the item's name:
std::string QuantityText = "\tx" + std::to_string(p.second);

//wide string that will be the button's text:
std::wstring wQText = wItemName + std::wstring(QuantityText.begin(), QuantityText.end());

//set the button's text (it takes wchar_t* so we call .c_str() on wQText):
itemButtons.at(bIndex).setText(wQText.c_str());

//draw the button with the temporary text to the screen:
itemButtons.at(bIndex).draw();

//poll if the button was clicked, and if it was,
//we will call useItem on it's corresponding Item:
if(itemButtons.at(bIndex).pollClicked()){
useItem(item);
}

//change the button's text back to what it was, note: there
//is a possibility of the button being removed after calling
//useItem() because when an item's quantity hits 0, the
//button corresponding with that item is removed, therefore
//we need a check after the useItem() call to make sure that
//we don't get an index out of bounds error:
if(ItemButtonsTextSearchC(wQText) != -1)
itemButtons.at(bIndex).setText(wItemName.c_str());
}
}
}
void Player::useItem(Item it){
int itemID = it.getItemID();
ItemAttributes(itemID);
}
void Player::ItemAttributes(int id){
switch(id){
case 0: //sword
//EquipedWeapon = Materials::getItem(id);
break;
case 1: //ultra potion of healing
healHP(50);
removeItem(id);
break;
}
}
bool Player::removeItem(int id){
//this will be set to true as soon as we find the item:
bool found = false;

//loop through ItemInventory and remove the first occurance of id
//if it exists, otherwise found will remain false:
for(int i = 0; i < ItemInventory.size(); i++){
if(ItemInventory.at(i) == id){
ItemInventory.erase(ItemInventory.begin() + i);
found = true;
break;
}
}

//if the item was not found in the inventory, there is no need to
//continue, we can just return false because we know that it isn't
//in the player's inventory so it can't be removed in the first place:
if(!found)
return false;

//get an iterator for the item ID's corresponding name in itemsList:
auto itr = ItemsList.find(Materials::itemNames[id]);

//check to make sure the item is actually listed; it will be
//but this is a safeguard in case something breaks:
if(itr != ItemsList.end()){
//decrement the item's quantity:
itr->second--;

//if there are none remaining, we remove it from the itemsList entirely:
if(itr->second <= 0)
ItemsList.erase(itr);
}

//update the buttons based on the new changes:
updateButtons();

//return true because if it got to this point,
//the item was found and removed:
return true;
}
int Player::ItemButtonsTextSearchC(const std::wstring& text){
if(itemButtons.size() > 0){
for(int i = 0; i < itemButtons.size(); i++){
std::wstring bTxt = itemButtons.at(i).getText();
if(bTxt.find(text) != std::string::npos)
return i;
}
}

return -1;
}
int Player::ItemButtonsTextSearch(const std::wstring& text){
if(itemButtons.size() > 0){
for(int i = 0; i < itemButtons.size(); i++){
std::wstring bTxt = itemButtons.at(i).getText();
if(bTxt == text)
return i;
}
}

return -1;
}
void Player::updateButtons(){
//first we clear the vector of itemButton:
itemButtons.clear();

//loop to go through each unique item in ItemsList map
//and make a button for each one:
for(auto& p : ItemsList){
//convert the item's name into a wstring (textbutton constructor takes wchar_t*, wstring is easier to work with):
std::wstring wName = std::wstring(p.first.begin(), p.first.end());

//add the new button to itemButtons
TextButton btn(sf::Vector2f(0, 0), sf::Color::Magenta, sf::Color::White, wName.c_str(), 18);

//make sure button presses only register once
btn.setWasClicked(true);

//add the button to the itemButtons vector:
itemButtons.push_back(btn);
}
}
bool Player::checkForItems(Room* r){
//itemIndex will == the ID of any item we collided with, if there
//was no item it returns -1
int itemIndex = r->checkForItemCollision(player.getGlobalBounds());

if(itemIndex >= 0){
//get item ID from the item we just collided with:
int itemID = r->getItem(itemIndex).collect();

//remove the item from the room and add it's ID to ItemInventory:
r->removeItem(itemIndex);
ItemInventory.push_back(itemID);

//get the item's name and add it to itemsList if it doesn't exist.
std::string itemName = Materials::itemNames[itemID];

//if the item's name is listed in itemsList, we increment it's
//quantity, else we add it and initialize it's quantity to 1:
if(ItemsList.count(itemName) != 0){
ItemsList.at(itemName)++;
} else {
ItemsList.insert(std::make_pair(itemName, 1));
}

//update the buttons in case a new item was obtained:
updateButtons();

//return true because item was found:
return true;
}

//return false, item wasn't found:
return false;
}

当我单击一个按钮时,它应该从 itemInventory 中删除该项目的数字 ID 的第一次出现,然后在 itemsList 中它应该减少数量( map 的值),如果它 <= 0,它应该完全删除它。 UpdateButtons 清除整个按钮 vector 并从 itemsList 中创建新的按钮,每个键一个按钮。 Item 类有一个枚举,说明它是什么类型的元素,剑(元素 ID 0)是武器,药水(元素 ID 1)是可用元素,当我点击剑(目前什么都不做)时,然后添加一个可用的项目(药水)并单击为可用创建的新按钮,它有一个错误。除非我先点击剑的按钮,否则不会发生这种情况,在任何其他情况下,当我使用所有元素时都不会出错,然后将更多元素添加到我的库存中并再次使用它们。我怀疑我更新按钮和删除 key 的方式有误,但我找不到它。所有项目类型都在相同的按钮 vector 中,项目类型几乎只决定按钮的位置。

最佳答案

Player::menu 中,您有一个循环,for(auto& p : ItemsList)。在该循环中,您调用序列 (useItem(item) -> ItemAttributes(itemID) -> removeItem(id) -> ItemsList.erase(itr)) 可以修改您正在迭代的 ItemsList map 。这会使当前引用 p 的迭代器无效,因此当您尝试访问映射中的下一个元素时,您会得到未定义的行为,因为(内部使用的)迭代器不再有效。

一种可能的补救措施是将您的 for 循环更改为使用您自己的迭代器,并在循环体顶部递增迭代器(在您修改映射之前):

for (auto it = ItemsList.begin(); it != ItemsList.end(); ) {
auto &p = *it;
++it;
// rest of for loop
}

关于c++ - 我的调试器说我有一个段错误但不能告诉我在哪里,发生在非常特殊的情况下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55390427/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com