So this is a reduced version of my main / Initializer function. When I call it and it has to add any items to the players inventor, I get a Debug Assertation Failed error.
It seems to me like I am mixing up the scope somewhat?
Am I declaring something new inside the scope of the function, and then not being able to access it again out in main?
I tried a few things inside the function, like using Getters/Setters instead of assigning is completely, like p_player = p but I don't think that actually deals with the problem at all, and I'm kind of confused.
int main()
{
Array<Item> items(3);
string itemsfilename = "itemsfile.txt";
Initializer::InitializeItems(items, itemsfilename);
Login login;
Player p1;
string filename = login.LoginToGame();
Initializer::InitializePlayer(p1, rooms, items, 3, filename);
}
void Initializer::InitializePlayer(Player& p_player, HashTable<string, Room>& p_rooms, Array<Item>& p_items, int p_numItems, std::string& p_filename)
{
ifstream playerfile(p_filename);
int inventorycount = 0;
//all the stuff needed to make a player
std::string name;
int health;
int confidence;
int humor;
int speed;
std::string room;
Room* currentRoom;
Inventory inventory(100);
//reading in values from file
for(int i = 0; i < inventorycount; i++)
{
playerfile.getline(value, 256);
std::string item(value);
for(int j = 0; j < p_numItems; j++)
{
if(p_items[j].GetName() == item)
{
inventory.AddItem(&(p_items[j])); //This line taken out, removes the error.
}
}
}
Player p(name, health, confidence, humor, speed, currentRoom, inventory);
p_player = p;
}
AddItem() takes a pointer to an item, and then appends it to it's DLinkedList.
Edit:
The error I get is
Debug Assertation Failed!
Program: zzz
File f:\dd/vctools/crt_bld/self_x86/crt/src/dbgdel.cpp
Line: 52
Expression: _Block_TYPE_IS_VALID(pHead->nBlockUse)
AddItem() Code:
bool AddItem(Item* p_item)
{
if(p_item->GetWeight() + m_weight <= m_maxWeight)
{
m_inventory.Append(p_item);
m_weight += p_item->GetWeight();
}
else
{
return false;
}
return true;
}
Ok, so we still don't have the code that actually causes the problem, but I'm pretty certain I know what's going on, and to avoid getting into a "20 questions of add more code" - there's two possible scenarios:
Items is an array of objects, and you store pointers to them in your m_inventory container. When destroying this container, the objects are destroyed by calling delete on the items - which doesn't work since the content is not allocated from the heap.
When you copy the inventory the m_inventory container is not appropriately copied, and the contents fall apart because the pointers to the storage is failing.
If this doesn't help, then please try to reduce your code to something that only shows this problem, without using files that we don't know the content of and can be posted as a complete program in the question with all the code necessary [remove any other code that isn't needed], so we can see EVERYTHING. Currently, we're only seeing a few bits of the code, and the problem is almost certainly DIRECTLY in the code you've shown us.
Related
So first all I'll preface this with: I just started using c++.
I have a structure that I store the pointer to in an unordered_map, setting members' values in the struct pointer as I get them through my process. Then I no longer need them in a map so I transfer then to a vector and loop through them.
Though on the second loop, it outputs my index (1) but the next statement of making a local pointer var for the struct at that index breaks it and the code terminates without any errors. since there are no errors then a try/catch doesn't give me anything either.
// Wanted to create a structure to handle the objects easier instead
// of multiple vectors for each property
struct appData {
std::string id = "";
std::string name = "";
std::string vdf_file = "";
std::string vdf_path = "";
};
// Relevant parts of my main()
int main() {
// Map that stores all the struct pointers
std::unordered_map<std::string, appData*> appDatas;
char memory[sizeof(appData)];
void* p = memory;
// New instance of appData
appData *tempAppData = new(p) appData();
tempAppData->appid = "86901";
// Add tempAppData to map with string key
appDatas["86901"] = tempAppData;
...
std::vector<appData*> unhashed_appDatas;
for (auto const& pair: appDatas) {
unhashed_appDatas.push_back(pair.second);
}
...
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
// Output index to see where it was messing up
std::cout << x << std::endl;
!! // This is where the issue happens on the second loop (see output)
appData *thisAppData = unhashed_appDatas[x];
std::string id = thisAppData->appid;
std::cout << id << std::endl;
/* ...
Do more stuff below
*/
}
...
return 0;
}
Terminal Output:
0 // Initial index of x
86901 // Id of first item
1 // New index of x on second loop before pointer var is created
// Nothing more is printed and execution terminates with no errors
My knowledge of c++ is pretty lacking, started it couple days ago, so the few things within my knowledge I've tried: moving the *thisAppData variable outside of the loop, using a for(var: vector) { ... }, and a while loop. I can assume that the issue lies with the pointer and the local variable when inside the loop.
Any help/input about how I could better approach this or if there's an issue with my code would be appreciated :)
Edit: Changed code to use .size() instead of sizeof() per #Jarod42 answer, though main issue persists
Edit2: Turns out it was my own mess-up, imagine that. 4Am brain wasn't working too well- posted answer regarding what I did incorrectly. Thanks to everyone who helped me
sizeof is the wrong tool here:
for (unsigned int x = 0; x < sizeof(unhashed_appDatas); x++) {
// ^^ wrong: give **static** size of the structure
// mainly 3 members (data, capacity, size), so something like `3*sizeof(void*)`
it should be
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
After many hours of trial and error I have determined the issue (aside from doing things in a way I should, which I've since corrected) it was something I messed up on that caused this issue.
TLDR:
Items wouldn't exist that I assumed did and tried to read files with a blank path and parse the contents that didn't exist.
Explaination:
In the first loop, the data I was getting was a list of files from a directory then parsing a json-like file that contained these file names and properties associated with them. Though, the file list contained entries that weren't in this other data file (since I had no check if they existed) so it would break there.
Additionally in the last loop I would get a member from a struct that would be the path of a file to read, but it would be blank (unset) because it didn't exist in data file so std::ifstream file(path); would break it.
I've since implemented checks for each key and value to ensure it will no longer break because of that.
Fixes:
Here are some fixes that were mentioned that I added to the code, which did help it work correctly in the end even if they weren't the main issue that I myself caused:
// Thanks to #EOF:
// No longer "using placement new on a buffer with automatic storage duration"
// (whatever that means haha) and was changed from:
char memory[sizeof(appData)];
void* p = memory;
appData *tempAppData = new(p) appData();
// To:
appData *tempAppData = new appData();
// Thanks to #Jarod42:
// Last for loop limit expression was corrected from:
for (unsigned int x = 0; x < sizeof(unhashed_appDatas); x++) {
}
// To:
for (unsigned int x = 0; x < unhashed_appDatas.size(); x++) {
}
// I am still using a map, despite comment noting to just use vectors
// (which I could have, but just would prefer using maps):
std::unordered_map<std::string, appData*> appDatas;
// Instead of doing something like this instead (would have arguably have been easier):
std::vector<std::string> dataKeys = { "1234" };
std::vector<appData*> appDatas = { ... };
auto indx = find(dataKeys.begin(), dataKeys.end(), "1234");
indx = (indx != dataKeys.end() ? indx : -1);
if (indx == -1) continue;
auto dataItem = appDatas[indx];
//
I appreciate everyone's assistance with my code
I have encountered this runtime exception at the very end of the program by simply creating an instance of the specified class, so I presume the issue lies with either the constructor, copy constructor, copy assignment operator or destructor. I have read up on and followed the rule of three to the extent of my limited cpp knowledge.
Source.cpp
#include "Header.h"
#include <iostream>
using namespace std;
int main() {
string command = "CREATE TABLE table_name IF NOT EXISTS ((column_1_name,type,default_value), (column_2_name,type,default_value))";
string columns[20] = { "column_1_name,type,default_value", "column_1_name,type,default_value" };
string commandData[9] = { "table_name", "IF NOT EXISTS" };
CommCREATETABLE comm(command, columns, commandData, 2, 2);
}
Relevant code from Header.h
class CommCREATETABLE {
string fullCommand = "";
string* columns = nullptr;
string* commandData = nullptr;
string tableName = "";
int nrOfColumns = 0;
int nrOfElements = 0;
bool valid = false;
Constructor:
CommCREATETABLE(string command, string* columns, string* commandData, int nrOfRows, int nrOfElements) {
this->setNrOfColumns(nrOfRows);
this->setNrOfElements(nrOfElements);
this->setCommand(command);
this->setColumns(columns);
this->setCommandData(commandData);
this->valid = checkInput(this->commandData, this->columns);
this->setTableName(commandData[0]);
}
Copy constructor, copy assignment operator, destructor:
CommCREATETABLE(const CommCREATETABLE& comm) {
this->setNrOfColumns(comm.nrOfColumns);
this->setNrOfElements(comm.nrOfElements);
this->setCommand(comm.fullCommand);
this->setColumns(comm.columns);
this->setCommandData(comm.commandData);
this->setTableName(comm.tableName);
this->valid = comm.valid;
}
~CommCREATETABLE() {
if (this->columns != nullptr) {
delete[] this->columns;
}
if (this->commandData != nullptr) {
delete[] this->commandData;
}
}
CommCREATETABLE& operator=(const CommCREATETABLE& comm) {
this->setCommand(comm.fullCommand);
this->setColumns(comm.columns);
this->setCommandData(comm.commandData);
this->setTableName(comm.tableName);
this->setNrOfColumns(comm.nrOfColumns);
this->setNrOfElements(comm.nrOfElements);
this->valid = checkInput(this->commandData, this->columns);
return *this;
}
The only setters that deal with dynamic memory allocation are the following:
void setColumns(const string* columns) {
if (this->nrOfColumns >= 0) {
this->columns = new string[this->nrOfColumns];
memcpy(this->columns, columns, this->nrOfColumns * sizeof(string));
}
else throw EmptyCommandException();
}
void setCommandData(const string* commandData) {
if (this->nrOfElements >= 0) {
this->commandData = new string[this->nrOfElements];
memcpy(this->commandData, commandData, this->nrOfElements * sizeof(string));
}
else throw EmptyCommandException();
}
At a quick glance I would say the issue is in your setColumns and setCommandData functions. (I might of course be wrong, I did not try to run the code you presented nor the changes I made -- so there might also be a typo somewhere.)
There you use memcpy to copy the strings into your class. However, internally a C++ string holds a pointer to the actual string, so using memcpy actually only copies that pointer. As a result, once the original string gets deleted, the pointer you copied into your class is no longer valid (as the memory has already been freed). As a result, once your class also gets deleted it attempts to delete memory that has already been freed. That is probably where your error comes from.
In fact, if you added lines to your program where you tried to manipulate your class (after the original input strings have already been deleted), the problem would present itself even sooner, as you would be accessing memory that has already been freed. This would lead to undefined behaviour, which typically ends with a crash at some point.
A quick fix would be to change the way you copy the data, by using = for each string (in that way copying the actual strings into a new location in memory, rather than copying the pointer).
void setColumns(const string* columns) {
if (this->nrOfColumns > 0) { // Creating an array of size 0 is also not a good idea.
this->columns = new string[this->nrOfColumns];
for (int i = 0; i < nrOfColumns; i++) { // You don't need this everywhere.
this->columns[i] = columns[i];
// I don't think naming things the exact same way is good practice.
}
}
else throw EmptyCommandException();
}
void setCommandData(const string* commandData) {
if (this->nrOfElements > 0) { // Creating an array of size 0 is also not a good idea.
this->commandData = new string[this->nrOfElements];
for (int i = 0; i < nrOfElements; i++) { // You don't need this everywhere.
this->commandData[i] = commandData[i];
// I don't think naming things the exact same way is good practice.
}
}
else throw EmptyCommandException();
}
Alternatively, if you want to avoid making copies you should look into move, but I would suggest against this for the time being, if you are still learning. You'll get there soon enough.
My homework is that I have to make a class (register) which contains 3 class arrays (birds, mammals, reptiles) which are in the animal class. Animal is the friend of Register. I will only show the birds part, to keep it simple.
The register class looks like:
class Register
{
Bird* birds;
unsigned int birdSize;
public:
...
}
The constructor of register:
Register::Register()
{
this->birds = new Bird[0];
this->birdSize = NULL;
}
Now I have a function in register that adds one element to the birds array, the input is cin.
void Register::add()
{
...
if (birdSize == 0)
{
birds = new Bird[0];
Bird* temp = new Bird[0];
temp[0].add();
this->birds = temp;
birdSize++;
}
else
{
Bird* temp = new Bird[birdSize+1];
for (unsigned int i=0; i<=birdSize; i++)
{
temp[i] = this->birds[i];
}
temp[birdSize+1].add();
birds = new Bird[birdSize+1];
birds = temp;
birdSize++;
}
temp[0].add() has the cin, it works properly. When I run the program, the user has to add 2 birds to the array. The problem occurs when reaching the part under 'else', so the second element of the array. The program surely reaches "temp[birdSize+1].add();" while running, then the "xyz.exe has stopped working" window pops up and it says in the details " Fault Module Name: StackHash_7e8e" so I'm sure something is wrong with the memory allocation, but the problem is that when I try to find the problematic line in debug mode, everything works fine.
Well, not everything. The program has a print() function, it prints out everything in Register. The second element of the array is the same as the first.
I have no clue what to do. I read many forum posts, read a cpp book, watched online tutorials, but I can't find the solution for this problem. Please help.
Array index starts from 0. So in else part you are writing
Bird* temp = new Bird[birdSize+1]; // size =birdSize +1;
So valid index range will be 0 -> birdSize, not birdSize+1.
The problem is
temp[birdSize+1].add();
you are using birdSize+1th index. It should be
temp[birdSize].add();
There are other bugs in your code:
for (unsigned int i=0; i<=birdSize; i++) // should be i<birdSize
{
temp[i] = this->birds[i];
}
There are other bad coding in your program:
Register::Register()
{
this->birds = new Bird[0]; // should be this->birds=NULL
this->birdSize = NULL; // should be this->birdSize = 0
}
And obviously if your homework does not demand it, you should not use arrays in this way. For variable size container, use vector, list.... Array is only when the size is fixed.
I have a vector with a list of commands as shown below:
//COMMAND INITIALISATION
std::vector<std::string> objectInitialisationAction;
objectInitialisationAction.push_back("CREATE"); //0
objectInitialisationAction.push_back("END_CREATE"); //1
objectInitialisationAction.push_back("START_TIMELINE"); //2
I only access this vector by using my function shown below:
int SearchFor(std::string search, std::vector<std::string> from)
{
int result=-1;
for(int i=0; i<from.size(); i++)
if(from[i]==search)
{
result=i;
break;
}
if(result == -1)
{
std::ofstream error("searching.txt");
error<<"search failed, original value = \""<<search<<"\""<<std::endl;
error<<"values in the table:"<<std::endl;
for(int i=0; i<from.size();i++)
error<<"value "<<i<<": "<<from[i]<<std::endl;
error.close();
}
return result;
}
With only one function call:
commandNum=SearchFor(command[0], objectInitialisationAction);
This is the only place where I access the vector, yet when I call the function for the nth time (it always brakes at the same point in the code) it accesses wrong and outputs gibberish. Some of the code I list below:
search failed, original value = "CREATE"
values in the table:
value 0: CREATE Øç¼ Œ Ôç¼ Œ Ðç¼ Exit ¼ç¼ ¸ç¼ Œ p«üxðù ; ´ç¼ Œ pëù#òø €< °ç¼ ŒBerlin Sans FB Demi e ¬ç¼ ˆ°¿^nmra œç¼ ŒBerlin Sans FB Demi e ˜ç¼ help ”ç¼ ˆ object_dump ç¼ test Œç¼ Ž spawn ˆç¼ ‹ load_map „ç¼ Ž
//and so on...
Any suggestions as to why a vector may corrupt like that?
It seems all correct. Compile and execute this. If it is all correct probably the problem is in another part of your code.
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int SearchFor(std::string search, std::vector<std::string> from)
{
int result=-1;
for(unsigned int i=0; i<from.size(); i++)
if(from[i]==search)
{
result=i;
break;
}
if(result == -1)
{
std::ofstream error("searching.txt");
error<<"search failed, original value = \""<<search<<"\""<<std::endl;
error<<"values in the table:"<<std::endl;
for(unsigned int i=0; i<from.size(); i++)
error<<"value "<<i<<": "<<from[i]<<std::endl;
error.close();
}
return result;
}
int main()
{
std::vector<std::string> objectInitialisationAction;
objectInitialisationAction.push_back("CREATE"); //0
objectInitialisationAction.push_back("END_CREATE"); //1
objectInitialisationAction.push_back("START_TIMELINE"); //2
for(unsigned int i=0; i<objectInitialisationAction.size(); i++)
{
cout<< objectInitialisationAction[i] << endl;
}
cout << "FOUND " << SearchFor("CREATE", objectInitialisationAction);
return 0;
}
I suggest you to add using namespace std; at the beginning of the file, so you have not to add std::blablabla on each declaration...your code will be more readable :) and please....INDENT IT :)
Your code looks correct to me. In this case, there should be another part of your application that corrupts the memory. For example, there could be an out-of-range array access, a dangling pointer or a use-after-delete somewhere. Tools like Valgrind might help you here.
The code looks ok as it is. The most likely scenario for me is that the length field of your strings gets unintentionally overwritten, because the command, i.e. the actual data, is still there. It's just that the string thinks it's longer than that. (Overwriting the characters wouldn't lead to the output you report: The commands would be overwritten, but the string length would still be short.) Overwriting memory typically happens through an array index or pointer which is out of bounds. The data it points to must have the same linkage as the strings (in your example local or global/static).
One strategy for bug searching would be to occasionally print the length of objectInitialisationAction's element strings; if they are too long you know something went wrong.
It may help to comment out code using a kind of binary search strategy (comment out one half -- mocking it's functionality to keep the prog running -- and look whether the error still occurs, then divide the faulty part again etc.).
Note that you pass the vector by value into SearchFor() which is perhaps unintended. The corruption may happen at the caller's or callee's side which should be easy to test.--
Hoped that helped.
try to pass all params through const refs:
int SearchFor(const std::string& search, const std::vector<std::string>& from)
{
...
}
I have a very strange issue. I have this code, which is supposed to loop until the end of the file. But it only loops exactly two times. It never finishes the while, but it reaches the end of the "if" or "else" sentence (depending on the file content).
Everything else is working "good", the numbers that are supposed to be going in are going in, and everything seems to be working until it doesn't reach the end of the while.
This is a futoshiki game. The code is supposed to read each line, treat it as a string, and then break it down into chars, which in turn are casted into integers (except for one char, being a less-than or greater-than sign), which make up the position of the cells or the positions between the signs. Then it uses that data to either add a new cell to the board or a new sign between cells.
The first line of a file is the size of the board.
This issue happens with several different files of different sizes, always on the second iteration. I'm running Linux by the way if it makes any difference.
int MainWindow::charToInt(char letter)
{
int number = letter;
return number - 48;
}
void MainWindow::locateInBoard(string data, board gameboard)
{
if (data.size()==3){
int number = charToInt(data[2]);
pair<int,int> coordinate(charToInt(data[0]), charToInt(data[1]));
gameboard.addCell(number,true,coordinate);
}
else{
pair<int,int> firstCoordinate(charToInt(data[0]), charToInt(data[1]));
pair<int,int> secondCoordinate(charToInt(data[2]), charToInt(data[3]));
gameboard.addSign(firstCoordinate, secondCoordinate, data[4]);
}
}
void MainWindow::getBoardFromFile(QString newString, board* ptToBoard)
/*
Each board has a file. The name of the file is determined by the size of the
board to play, the difficulty and the number of board. The text file contains the
sign and numbers of the board. Let's say the number 3 is in position (2,1), then the
file should contain a line "213". For signs, if there is a > between (3,3) and (3,4),
the file should have a line "3334>"
*/
{
QFile file(newString);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){
return;
}
QTextStream in(&file);
QString line = in.readLine();
size = line.toInt();
board gameboard(size);
string stdline;
while (!in.atEnd()) {
line = in.readLine();
stdline = line.toStdString();
locateInBoard(stdline,gameboard);
}
*ptToBoard = gameboard;
}
And this is the relevant code of "board".
board::board(int n)
{
boardSize = n;
gameboard = new cell*[boardSize];
for (int i = 0; i<boardSize; i++){
gameboard [i] = new cell[boardSize];
}
pair<int,int> newPosition;
for (int i = 0; i<boardSize; i++){
newPosition.first = i;
for (int j = 0; j<boardSize; j++){
newPosition.second = j;
gameboard[i][j].setPosition(newPosition);
}
}
}
void board::addCell(int number, bool fixed, pair<int,int> position)
{
cell newCell(number,fixed,position);
gameboard[position.first][position.second] = newCell;
}
void board::addSign(pair<int,int> firstPosition, pair<int,int> secondPosition, char sign)
{
cell firstCell = gameboard[firstPosition.first][firstPosition.second];
cell secondCell = gameboard[secondPosition.first][secondPosition.second];
gameRules.setUnequality(firstCell,secondCell,sign);
}
I know it's not pretty, but I should've handed this in Wednesday and it's three am Thursday and I really don't care anymore if it's pretty or hard-coded as long as it's working.
Thanks a lot for your help, I'm really desperate here.
Take a look at the signature of your locateInBoard method:
void MainWindow::locateInBoard(string data, board gameboard)
That's passing the board by value. So all changes made to the board in locateInBoard are applied to a local copy, which will just get thrown away when the function completes.
Try pass-by-reference instead:
void MainWindow::locateInBoard(string data, board & gameboard)
In addition, I'm worried about this:
board gameboard(size); // created locally
// ... lots of processing ...
*ptToBoard = gameboard; // copy using assignment operator
This is something that can work, but you have to make sure your board class correctly supports copying data. C++ generates default assignment operators if you don't write your own, but they don't work for anything other than trivial structures. You'll likely need to implement your own assignment operator or change your code to avoid using assignment or a copy constructor.
Here's a quick alternative that avoids needing to figure out how to write your own operator=:
board * MainWindow::getBoardFromFile(QString newString)
{
// ...
board * gameboard = new board(size);
// ... do all of your stuff ...
// you'll need to change your existing code to use -> instead of .
// if you get an error, return 0 or throw an exception
return gameboard;
}
(If you don't want to support copy constructors and operator=, it's good practice to write your own anyway — just make them do nothing and markthem private in your header. This'll allow the compiler to help you catch unintended copying.)