Note, problem has been identified, refer to second section for current detail and the third section for the most likely reason and a question on how to remedy it
I'm writing a program in Qt and I stopped a couple days ago at a segmentation fault problem. It seemed to complain about memory not being allocated. I searched around and couldn't figure out why there was an allocation problem and I took a break. Now, looking at it again, the segmentation fault is still there, but it's in a completely different, mostly unrelated function. What could be causing these random segmentation faults?
For some concreteness, in this case, I am currently getting a segmentation fault here:
Q_DECL_CONSTEXPR inline int QSize::height() const
{ return ht; }
I was getting it here before I commented out the lines (the last three lines)
qDebug() << QString("---SETTINGS DEBUG---")+QString("\r\n")<<
"netProcPage: "+netProcPage.url()+"\r\n" <<
"mapSize.width(): "+QString::number(mapSize.width())+"\r\n"<<
"mapSize.height(): "+QString::number(mapSize.height())+"\r\n"<<
"mapZoom: "+QString::number(mapZoom)+"\r\n"<<
"mappxSize.width(): "+QString::number(mappxSize.width())+"\r\n"<<
"mappxSize.height(): "+QString::number(mappxSize.height())+"\r\n"<<
"UserCoords[0]: "+QString::number(UserCoords[0])+"\r\n"<<
"UserCoords[1]: "+QString::number(UserCoords[1])+"\r\n"<<
"mapCoordOffsets[0]: "+QString::number(mapCoordOffsets[0])+"\r\n"<<
"mapCoordOffsets[1]: "+QString::number(mapCoordOffsets[1])+"\r\n"<<
"getWindowSize.width(): "+QString::number(getWindowSize.width())+"\r\n"<<
"getWindowSize.height(): "+QString::number(getWindowSize.height())+"\r\n"<<
"mappxOffsets[0]: "+QString::number(mappxOffsets[0])+"\r\n"<<
"mappxOffsets[1]: "+QString::number(mappxOffsets[1])+"\r\n"<<
QString("---END SETTINGS DEBUG---")+QString("\r\n");
Before then, without changing anything (just waiting a couple days and a couple restarts later), it was here:
mkeMap.genMap(QString("Map1"), tempmapSize, tempmapZoom, mapDisp->ui);
In the MainWindow class constructor complaining about tempmapSize, which is defined by:
QSize tempmapSize;
tempmapSize = settings->mapSize; //<--- The error might be coming from here, is there an alternative?
which is where the segmentation faults have been associated with. This is the settings class:
#include "settings.h"
Settings::Settings(QWidget *parent)
{
netProcPage = "http://localhost:81";
// Max image size is 32767x32767 pixels (divided by 4*mapZoom since 4 panes are used at mapZoom zoom)
// If max mapZoom is 20, max size of map is 409x409, or 408x408 to keep it even
mapSize.setWidth(250);
mapSize.setHeight(250);
mapZoom = 10;
mappxSize.setWidth(mapSize.width()*mapZoom);
mappxSize.setHeight(mapSize.height()*mapZoom);
//downloadMap(netProcPage,"getMap","Username","Password");
//makeMap("bingbong",mapSize,mapZoom);
UserCoords[0] = 0;
UserCoords[1] = 0;
mapCoordOffsets[0] = UserCoords[0] + .5 * mapSize.width();
mapCoordOffsets[1] = UserCoords[1] + .5 * mapSize.height();
//getWindowSize.setWidth(parent->width());
//getWindowSize.setHeight(parent->height());
getWindowSize.setWidth(500);
getWindowSize.setHeight(500);
mappxOffsets[0] = UserCoords[0]*mapZoom + .5 * getWindowSize.width() - .5 * mappxSize.width();
mappxOffsets[1] = UserCoords[1]*mapZoom + .5 * getWindowSize.height() - .5 * mappxSize.height();
}
void Settings::debug()
{
qDebug() << QString("---SETTINGS DEBUG---")+QString("\r\n")<<
"netProcPage: "+netProcPage.url()+"\r\n" <<
"mapSize.width(): "+QString::number(mapSize.width())+"\r\n"<<
"mapSize.height(): "+QString::number(mapSize.height())+"\r\n"<<
"mapZoom: "+QString::number(mapZoom)+"\r\n"<<
"mappxSize.width(): "+QString::number(mappxSize.width())+"\r\n"<<
"mappxSize.height(): "+QString::number(mappxSize.height())+"\r\n"<<
"UserCoords[0]: "+QString::number(UserCoords[0])+"\r\n"<<
"UserCoords[1]: "+QString::number(UserCoords[1])+"\r\n"<<
"mapCoordOffsets[0]: "+QString::number(mapCoordOffsets[0])+"\r\n"<<
"mapCoordOffsets[1]: "+QString::number(mapCoordOffsets[1])+"\r\n"<<
"getWindowSize.width(): "+QString::number(getWindowSize.width())+"\r\n"<<
"getWindowSize.height(): "+QString::number(getWindowSize.height())+"\r\n";//<<
//"mappxOffsets[0]: "+QString::number(mappxOffsets[0])+"\r\n"<<
//"mappxOffsets[1]: "+QString::number(mappxOffsets[1])+"\r\n"<<
//QString("---END SETTINGS DEBUG---")+QString("\r\n");
}
QSize* Settings::getmapSize()
{
return &mapSize;
}
int Settings::getmapZoom()
{
return mapZoom;
}
---
Here's the problem (identified)
I've refactored the code as suggested and I have pinpointed the exact problem, but I don't know how to fix it.
void makeMap::genMap(QString name, QPointF* inSize, int* zoom, Ui::MapDisp* ui)
{
QVector<QString> mapvector;
QPointF mapSize = *inSize; // <--- The problem is right here
...
}
The problem occurs when dereferencing the QPointF object found in an earlier instance of Settings, which was sent to genMap(...).
The call was done like this:
QPointF* tempmapSize;
tempmapSize = settings->getmapSize();
int* tempmapZoom = settings->getmapZoom();
mkeMap.genMap(QString("Map1"), tempmapSize, tempmapZoom, mapDisp->ui);
Wherever I moved the dereference (*Settings::inSize*, or *inSize), that's where the error occurred (in the debugger). Everything has been compiling fine.
When running the program, it crashes with this error:
Starting C:\program-debug.exe...
ASSERT failure in QVector<T>::operator[]: "index out of range", file ../../../../../Qt/5.2.0/mingw48_32/include/QtCore/qvector.h, line 369
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
C:\program-debug.exe exited with code 3
This reference to QVector<T> is referring to later in genMap,
void makeMap::genMap(QString name, QPointF* inSize, int* zoom, Ui::MapDisp* ui)
{
QVector<QString> mapvector;
QPointF mapSize = *inSize; //<---Here's the segmentation fault
/* Using this instead of the above works, as well as replacing zoom which causes another segmentation fault when dereferenced
QPointF mapSize;
mapSize.setX(250);
mapSize.setY(250);
int zoom0 = 10;
*/
QFile file(name+"_"+QString::number(mapSize.x())+"x"+QString::number(mapSize.y())+".rtsmap");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
mapvector.resize(mapSize.x() * mapSize.y());
for(int x = 0; x < mapSize.x(); x++){
for(int y = 0; y < mapSize.y(); y++){
uint decimalcolor = (((qSin(x)+1) + (qSin(y)+1))/4)>1?16777215:(((qSin(x)+1) + (qSin(y)+1))/4)*16777214;
QString hexadecimalcolor;
hexadecimalcolor.setNum(decimalcolor,16);
mapvector[index(x, y, mapSize)] = "#" + hexadecimalcolor;
//drawRect(x*10,y*10,10,10,"#"+hexadecimalcolor,zoom);
out << "#" << hexadecimalcolor+'\n';
}
}
file.close();
drawMap(mapvector,zoom0,ui,mapSize);
}
In Short
I think the problem is a dangling pointer. More specifically, when I pass the settings pointer to the class constructor, here:
MapCtrl::MapCtrl(QWidget *parent, Settings *settingsIn) :
QWidget(parent),
ui(new Ui::MapCtrl)
{
ui->setupUi(this);
mapDisp = new MapDisp(parent, settingsIn);
addMap();
settings = settingsIn;
}
The pointer settingsIn probably gets deleted at the end of the constructor with settings still pointing there, so later when I dereference a value from settings, it doesn't exist, causing a segmentation fault. So, the question is, how do I prevent the pointer called settingsIn from getting deleted at the end of the constructor?
requested code
Here's where the MapCtrl construtor MapCtrl::MapCtrl gets invoked and Settings is instantiated:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
wScr = new WelcomeScreen(this);
Settings *settings = new Settings(this);
mapCtrl = new MapCtrl(parent,settings);
...
}
solution (thanks to Kuba Ober for the guidance and the plethora of useful C++ knowledge)
In addition to checking for dangling pointers and fixing some possible causes, the final step was to change this:
MapCtrl::MapCtrl(QWidget *parent, Settings *settingsIn) :
QWidget(parent),
ui(new Ui::MapCtrl)
{
ui->setupUi(this);
mapDisp = new MapDisp(parent, settingsIn);
addMap();
qDebug() << "bingbong!!" << settingsIn->mapSize.x();
settings = settingsIn;
}
to this:
MapCtrl::MapCtrl(QWidget *parent, Settings *settingsIn) :
QWidget(parent),
ui(new Ui::MapCtrl)
{
ui->setupUi(this);
mapDisp = new MapDisp(parent, settingsIn);
qDebug() << "bingbong!!" << settingsIn->mapSize.x();
settings = settingsIn;
addMap();
}
settings was being set after a function that needed settings to be set.
In your entire codebase:
Get rid of places where you return Qt containers (QSize, QList, etc.) by pointer, and replace them with returning them by value.
Declare accessor methods const.
E.g. change Settings::getmapSize() to the below, idiomatic, code:
QSize Settings::getmapSize() const
{
return mapSize;
}
Use QPointF for coordinates, instead of naked arrays. Pass those into methods/functions by either value or const reference; the former may actually work a tad faster on modern hardware and compilers.
E.g. change the code in the constructor to be like this:
mapCoordOffsets = UserCoords + (toPoint(mapSize) * .5);
Where
static QPointF toPoint(const QSize & size) {
return QPointF(size.width(), size.height());
}
Get rid of the C-style output parameters, like in
void makeMap::genMap(..., QPointF* inSize, int* zoom, ...)
If you're returning something, simply return a structure that's called, say MapParams or somesuch:
MapParams makeMap::genMap(...);
If you're taking a structure and potentially modifying it, just modify it and return the modified one:
MapParams makeMap::genMap(..., MapParams params) {
...
params.size = ...;
params.zoom = ...;
...
return params;
}
My worry is that somewhere you're passing a bogus pointer or otherwise a pointer is obfuscating a lifetime issue. Naked pointers in modern C++ are highly suspect, and your code seems to use a lot of them for no good reason at all. Output parameters implemented with pointers are C-ism that has no place in modern C++.
Another common bug could be this: you have a Settings * settings member in the MainWindow class. Then you happily create a Settings * local variable in MainWindow constructor, but the MainWindow::settings member remains uninitialized. That's why you should always prepend member names with m_, so that they are harder to confuse with local variables. Ideally, you should use initializer lists to initialize members in a constructor.
When doing debugging, when you see an assert about out-of-bounds access, you need to debug its cause. A debugger should stop on such an assert, if not then you've got something misconfigured (what's your exact platform and toolset?). Whatever happens afterwards is meaningless if it was a write access, as memory has been overwritten, and you're chasing squirrels at this point.
Doing those things cuts down a whole bunch of errors that you've possibly made in your code. It may not fix your problem, but will get you on a good trajectory towards the solution.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
This is basically my main function :
void GameObject::deserialize(QList<GameObject*> *list)
{
QFile _file(_filename);
if (!_file.open(QIODevice::ReadOnly | QFile::Text))
{
qDebug() << "Couldn't open file to read";
return;
}
QTextStream in(&_file);
while (!in.atEnd())
{
QString currentline = in.readLine();
if (currentline.startsWith("GameObject {"))
{
list->append(getGameObject(&in, currentline));
}
}
_file.close();
}
It opens a file, and parses it for GameObjects.
The getGameObject (cleaned up) function is this one :
GameObject *GameObject::getGameObject(QTextStream *in, QString current_line)
{
GameObject *go = new GameObject();
QList<GameObjectVariable*> govl;
bool ok;
while (!in->atEnd() && !current_line.startsWith("} end GameObject"))
{
current_line = in->readLine();
if (current_line.startsWith("GameObjectVariable")) {
GameObjectVariable *gov = this->getGameObjectVariable(in, current_line);
govl.append(gov);
go->setVariableList(&govl);
qDebug() << QString("AR : Type As String of the returned object : ") + gov->getTypeAsAString();
qDebug() << QString("AR : Type as number : ") + QString::number(gov->getType());
if (gov->getType() == NUMBER_LIST) {
qDebug() << "Number List";
qDebug() << QString("Value as a string of the number list : ") + ((GameObjectVariableNumberList*)gov)->getValueAsAString();
}
else if (gov->getType() == STRING_LIST) {
qDebug() << "String List";
qDebug() << QString("Value as a string of the string list : ") + ((GameObjectVariableStringList*)gov)->getValueAsAString();
}
else if (gov->getType() == GAMEOBJECT) {
qDebug() << "GameOBject";
qDebug() << QString("Value as a string of the gameobject : ") + ((GameObjectVariableGameObject*)gov)->getValueAsAString();
}
}
}
return go;
}
This one basically is a big mess of ifs, but it works, up to a point. The goal of this function is to read line by line, and return a gameobject filled with the read info. This is a weird format we use for the project though.
The last bunch of lines are Debug lines I've put in to try to understand where the problem was.
This is the other (cleaned up) function that's related :
GameObjectVariable* GameObject::getGameObjectVariable(QTextStream *in, QString current_line)
{
GameObjectVariable *gov;
bool ok;
int type;
QList<QString> ls;
QList<int> ln;
QList<GameObject*> lgo;
while (!in->atEnd() && !current_line.startsWith("} end GameObjectVariable")) {
current_line = in->readLine();
if (current_line.startsWith("type: "))
{
type = current_line.right(current_line.size() - 5).toInt(&ok, 10);
}
else if (current_line.startsWith("value: ")) {
if (current_line.startsWith("value: {"))
{
while (!in->atEnd() && !current_line.startsWith("} end value"))
{
current_line = in->readLine();
if (!current_line.startsWith("} end value"))
{
if (type == GAMEOBJECT_LIST)
{
lgo.append(getGameObject(in, current_line));
}
else if (type == STRING_LIST)
{
ls.append(current_line);
}
else if (type == NUMBER_LIST)
{
ln.append(current_line.toInt(&ok, 10));
}
}
}
if (type == GAMEOBJECT_LIST)
((GameObjectVariableGameObjectList*) gov)->setValue(&lgo);
else if (type == STRING_LIST)
((GameObjectVariableStringList*) gov)->setValue(&ls);
else if (type == NUMBER_LIST)
((GameObjectVariableNumberList*) gov)->setValue(&ln);
}
}
}
qDebug() << QString("BR : Get the type as string : ") + gov->getTypeAsAString();
qDebug() << QString("BR : Get the type as number : ") + QString::number(gov->getType());
qDebug() << QString("BR : get the value as string of the object : ") + gov->getValueAsAString();
return gov;
}
This function reads the lines in the GameObjectVariable 'tag'. The type is a defined int that is macroed to the text type we use for the other if forest.
Now this again works fine, except for when we have a list of values (the part that starts with else if (current_line.startsWith("value: {"))).
The debug lines at the end of the function (the "BR :" ones) show the object properly filled, but the ones at the end of the getGameObject calling function (starting with "AR :") crash, because apparently the value is null.
GameObjectVariable object is this one (again, cleaned up) :
class GameObjectVariable
{
public:
GameObjectVariable(QString name, QList<int> idListEdit = QList<int>(), QList<int> idListView = QList<int>());
// GETTERS
QString getName() {return this->name;}
int getType() {return this->type;}
void *getValue() {return this->value;}
// SETTERS
void setName(QString name) {this->name = name;}
void setValue(void* value) {this->value = value;}
QString getTypeAsAString();
virtual QString getValueAsAString() = 0;
private:
QString name;
protected:
void *value;
int type;
};
getValueAsAString is set as virtual because every type mentioned in the code above (like GameObjectVariableStringList overwrite this one with a return of their value with the correct type)
Finally, here is an example of file we try to deserialize :
GameObject {
name: Number 1
type: Test
GameObjectVariableStringList: {
type: 3
name: List String
value: {
String 1
String 2
} end value
} end GameObjectVariable
(type: 3 corresponds to STRING_LIST)
The main problem is bolded.
The problem
getGameObjectVariable()'s local variable GameObjectVariable *gov is an uninitialised pointer, which you suddenly cast to some other type and then start trying to call methods on.
How did you expect that to end? You are telling the compiler this: Poke at random memory as if it holds an allocated, initialised object. Also, this object might have any of 3 different types.
Seriously: What did you think was happening in that function, that it was somehow producing a usable object? I'm genuinely curious.
Anyway, for at least three reasons, this is malformed code that exhibits completely undefined behaviour:
The pointer is uninitialised, so like any uninitialised variable, reading/dereferencing it is UB.
No object is alive at the (invalid) address to which it points, but you call methods on it as if an object lives there; that is UB.
Said methods then presumably start writing stuff to whatever arbitrary address you happened to end up at, with no permission, which is lethal UB.
(Also, even if there was valid memory to access and a valid object at it, casting the pointer to another type then using it is only valid if an instance of that other type was specifically allocated at that address - or some more-derived one, but then the C-style cast is (A) bad style and (B) potentially very dangerous if e.g. multiple and/or virtual inheritance are in play.)
Due to all this UB, anything can happen, or nothing might happen, or exactly what you want just might happen - but the code is fundamentally broken.
For example, as seems to have occurred here, the compiler might coincidentally act like there is a valid object while within the same function, but then you return that garbage pointer to getGameObject(), and it suddenly reveals that you fed it rubbish.
UB gives the compiler, and particularly its optimising layers, free reign to do whatever they want, chiefly because they are allowed to assume UB does not happen. So, e.g. they can assume there must be a valid object pointed to by gov, even if there blatantly isn't. That assumption gets lost after you return, though, for whatever reason.
Who knows? The precise reasons for the observed behaviour are pretty uninteresting to speculate about. You can produce assembly output if you really want to know why what happened happened.
The (immediate) solution
But the key point is this: You need to replace this particular mess with proper, valid code - and fast. So, you need to assign a valid value to the pointer, by assigning it the address of a newly allocated object of whichever type is required. Only then do you have an address to which you are allowed access, with a living object at it, of the right type. It's then OK to create a cast pointer of the real derived type to call derived methods, but return a pointer-to-base for others to use.
Conditionally calling methods, etc.
Also, those conditional casts and calls to setValue() look suspicious. Why not just make that a virtual method and let the compiler resolve the right variation? Generally, if you have some conditional construct deciding which method to call based on the real type... You should just use virtual functions. Most concern about their overhead is FUD, and most attempts to avoid that overhead are no more efficient to execute and much worse to read.
For instance, do you expect all users of any GameObjectVariable to repeat the same hoop-jumping exercise of checking what type it is and casting to the equivalent type of pointer to call the right (derived, hiding-not-overriding) version of setValue()? Hello, boilerplate spaghetti code, for no reason.
I think this points at more general bad patterns in your design. Rather than having huge functions that repeatedly have to check the type and do different things, with different lists depending on the type, etc. - why not simply check the type specified by the input line, and construct a new object of that type with, for example, the rest of the line as an argument, letting it create and populate whatever type of list and any other specific attributes it needs? Then you'll have tidy methods that do single things, not labyrinths that must constantly remind themselves what kind of object they're working with.
Avoid new
Note that I said said to assign the pointer from "a newly allocated object", not a newly allocated object... Most people should not ever need to use raw new or delete in C++, so you should return a unique_ptr, ideally from std::make_unique<Foo>(args).
There is a fair exception if, as hyde points out in the comments, your new object is of a type that should have its lifetime managed by a parent object to which it is then added. Then new is OK - assuming there's no better way to phrase it, like I dunno, make_floating_reference<Foo>(args). But, as hyde also said, that isn't the case for your GameObjectVariable, so a smart pointer is the way to go for that.
(Normally I would say you probably don't need dynamic allocation at all, but since you appear to need polymorphism and the objects clearly don't comprise a known set on the stack to which you could push non-owning pointers/reference-wrappers into the container, it seems that you do.)
I am testing this library but I am getting a segmentation fault whenever it reachs a certain line (the commented one below). This issue comes from this question - tldr the same problem on a much bigger project, so I decided to test the libraries separatedly and apparently this is what fails. This code works on a co-worker's 32bits machine using Qt4 (he handed me the code). I migrated it to Qt5 and compiled with a 32bit compiler and I am getting the segmentation fault. If I comment the offending line and the two below it the program runs (although its just an empty window).
What could be happening?
#include "qenctest.h"
#include <QLibrary>
#include <QtWidgets/QMessageBox>
typedef void (*encRefresh)(QPainter*);
encRefresh enc_refresh = NULL;
typedef void (*encResize)(QSize);
encResize enc_resize = NULL;
typedef QENCSignaler* (*encInit)(QString);
typedef void (*encOpenFile)(QString);
QENCTest::QENCTest(QWidget *parent, Qt::WindowFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
QLibrary _qenc("qenc");
encInit enc_init;
encOpenFile enc_openFile;
enc_init = (encInit) _qenc.resolve("init"); // I checked and it does load the library and the symbol succesfully
enc_openFile = (encOpenFile) _qenc.resolve("openFile");
enc_resize = (encResize) _qenc.resolve("resize");
enc_refresh = (encRefresh) _qenc.resolve("refresh");
QString path = "encfg";
QENCSignaler* qencSignaler = enc_init(path); // Throws segfault here
connect(qencSignaler, SIGNAL(newChart(Chart*)), this, SLOT(qencNewChart(Chart*)));
connect(qencSignaler, SIGNAL(startReadChart(char*)), this, SLOT(qencStartReadChart(char*)));
enc_openFile("PL2BAPOL.000");
int _s = 0;
}
Debug info:
PS: What does it mean that some locals & expressions are in red?
EDIT
Alright, the only major changes I had to make in the library code were these:
AttributeSet::iterator vItPOI = attributes.at(i).find("POI");
if (vItPOI == attributes.at(i).end()) continue;
AttributeSet::iterator vItPOI0 = attributes.at(i).find("POI0");
if (vItPOI0 == attributes.at(i).end()) continue;
if (vItPOI -> getStringValue() == "Bankowoæ" &&
selectedPOI & POI_BANKING) {
if (vItPOI0 -> getStringValue() == "Placówka banku") {
drawSymbol(painter, x, y, POI_BANKING);
}
}
To this (there are more ifs but this illustrates it properly)
ShapeAttribute vItPOI = attributes.at(i).find("POI").value();
if (attributes.at(i).find("POI") == attributes.at(i).end()) continue;
ShapeAttribute vItPOI0 = attributes.at(i).find("POI0").value();
if (attributes.at(i).find("POI0") == attributes.at(i).end()) continue;
if (vItPOI . getStringValue() == "Bankowo��" &&
selectedPOI & POI_BANKING) {
if (vItPOI0 . getStringValue() == "Plac�wka banku") {
drawSymbol(painter, x, y, POI_BANKING);
}
}
In theory it should be the same shouldnt it? Although I do find strange that in the first snippet it uses -> instead of . when its not a pointer. I had to change it to that because I was getting these errors:
^
..\qenc\ShapeLandPOI.cpp: In member function 'virtual void ShapeLandPOI::draw(QPainter*)':
..\qenc\ShapeLandPOI.cpp:74:62: error: conversion from 'QMap<QString, ShapeAttribute>::const_iterator' to non-scalar type 'QMap<QString, ShapeAttribute>::iterator' requested
AttributeSet::iterator vItPOI = attributes.at(i).find("POI");
^
..\qenc\ShapeLandPOI.cpp:76:64: error: conversion from 'QMap<QString, ShapeAttribute>::const_iterator' to non-scalar type 'QMap<QString, ShapeAttribute>::iterator' requested
AttributeSet::iterator vItPOI0 = attributes.at(i).find("POI0");
^
In your changed code you have the line
ShapeAttribute vItPOI0 = attributes.at(i).find("POI0").value();
But if "POI0" is not found the find function would return end which is an iterator pointing to beyond the collection, and so it's value function would be causing undefined behavior.
As for the errors it seems that the QMap object is constant, and so you can't get non-const iterators. Just change to use AttributeSet::const_iterator instead and you can use the original function otherwise unmodified. This will probably fix your crashes, as then you don't have the risk of undefined behavior as described above.
I'm trying to streamline my code and make it work better and easier:
This means diving into vectors and unique_ptr, about which I've read so many good things. However, they are entirely new to me. I have read a few pages on both, but its a lot to wrap my head around.
What I'm currently doing is creating objects of abstract class the traditional way:
VirtualBaseClass* foo1= new DerviedClass1;
VirtualBaseClass* foo2= new DerviedClass2;
VirtualBaseClass* foo3= new DerviedClass3;
But since I have 3 - and quite possibly will have lots more - I want to make it easier to switch between them because I'm going to be comparing any combination of the objects each program run.
Currently, to switch, I just rename the DerviedClass for which I want to instantiate an object so I don't have to go in renaming each foo1 with foo3, etc..
VirtualBaseClass* Generic1 = new DerviedClass3;
VirtualBaseClass* Generic2 = new DerviedClass1;
But ultimately I want the user to tell the program which two objects to compare. So a good starting point seems to make this an array of the VirtualBaseClass, but from research it seems like its pain to have to delete the arrays so people recommend using smart pointers and vectors.
So I tried to use both. For unique pointers I do
unique_ptr<vBaseClass*> foo1(DerviedClass1);
unique_ptr<vBaseClass*> foo2(DerviedClass2);
unique_ptr<vBaseClass*> geneic1 = move(foo1);
However, from what I read I should be doing
unique_ptr<vBaseClass*> foo1(new DerviedClass1);
but new gives error of type specfier but since it works without it I think nothing of it.
With move(foo1) I get an error no move for instance of overload function match and on compile a whole host of other errors such as
unique_ptr<vBaseClass*> champ1 = move(foo1);
error C3867: 'Controller::foo1': function call missing argument list; use '&Controller::foo1' to create a pointer to member
error C2780: '_OutTy *std::move(_InIt,_InIt,_OutTy (&)[_OutSize])' : expects 3 arguments - 1 provided
All this is being done in my Controller.h file btw.
I'm in desperate need of guidances. I don't know if what I'm doing is even neccsary, do I need to use vectors with this? How would I even begin too? Is there a better way of doing this? How do I even get the user to tell the program which object to use? With arrays it would be enter 0 for foo1 or enter 1 for foo2 but with vectors? Is there a better way?
My acutal code
#pragma once
#include "stdafx.h"
#include "Skarner.h"
#include "MasterYi.h"
#include "Riven.h"
using namespace std;
class Controller
{
public:
Controller();
~Controller();
double PCFreq;
__int64 CounterStart;
int CounterCheck;
ofstream out;
Champion* skarner = new Skarner;//old way of doing it
//Champion* yi = new MasterYi;//old way of doing it
//Champion* riven = new Riven;//old way of doing it
//Champion** champions = new Champion*[200];
//Champion[0] = new Skarner();
//unique_ptr<Champion> skarner(Skarner);
unique_ptr<Champion> yi(new MasterYi);// doesn't work new error
unique_ptr<Champion*> riven(Riven); //works with or without *
unique_ptr<Champion*> champ1 = move(riven)//error with move
vector<unique_ptr<Champion>> pChampions;//vector of pointers to champion
//unique_ptr<Champion> champ2;
//Champion *champ1 = dynamic_cast<Champion*>(yi);
//Champion *champ2 = dynamic_cast<Champion*>(skarner);//not sure what the signficance of this is
//Leaving some methods out
};
Wow so apparently you can't use the "new" in a header file only in the cpp file. However I'm still not sure how to make good use of it now that I have it declared in the controller.cpp? I really wanted it as a member variable/instance variable.
Trying to do this. in controller.h
shared_ptr<Champion> yi;
shared_ptr<Champion> riven;
shared_ptr<Champion> skarner;
shared_ptr<Champion> champ1;
shared_ptr<Champion> champ2;
and in the .cpp to define them
Controller::Controller()
{
PCFreq = 0.0;
CounterStart = 0;
out.open("finalStats.txt");
CounterCheck = 0;
yi = shared_ptr<Champion> (new MasterYi);
riven = shared_ptr<Champion>(new Riven);
skarner = shared_ptr<Champion>(new Skarner);
champ1 = move(yi);
champ2 = move(riven);
}
The above code now seems to work but I'm failing to see any direct benefits.
Explanation
You got a * to much:
unique_ptr<vBaseClass> foo1(new DerivedClass1);
should do the trick by allocating a new DerivedClass1 with dynamic storage duration and storing the pointer to it in foo1.
As a reminder, just read the type aloud: foo1has type "unique pointer to vBaseClass".
For the crowd in the comments
The following shows the difference in usage between a raw pointer and a unique pointer:
{
int* a = new int(42);
unique_ptr<int> b(new int(42));
std::cout << *a << ", " << *b << "\n";
delete a;
}
There is no further difference. Any further problem you have is related to a different problem that is hard to pinpoint without further information.
Also, unique_ptr<Champion*> riven(Riven); is a function declaration for a function by the name of riven returning a unique_ptr<Champion*> and taking a single argument of type Riven. The reason this does not error is because it does not do what you think it does at all.
Finally, there is absolutely nothing that makes headers anything special. In fact, C++ performs text substitution before parsing, so that the actual parser does not even know anything about where the code came from anymore!
Karmic Demonstration
Code:
struct champ { virtual std::string whoami() = 0; };
struct karma : champ { std::string whoami() override { return "karma"; } };
int main() {
champ* a = new karma;
std::unique_ptr<champ> b(new karma);
std::cout << a->whoami() << ", " << b->whoami() << "\n";
}
Result:
karma, karma
Proof
unique_ptr<Champion> yi(new MasterYi);// doesn't work new error looks like a function declaration to the compiler, and new isn't valid in that context.
unique_ptr<Champion*> riven(Riven); //works with or without * also looks like a function declaration and is valid with or without the *.
unique_ptr<Champion*> champ1 = move(riven)//error with move You can't move a function into a unique_ptr.
I'm having a really hard time understanding your question but maybe you mean something like this:
unique_ptr<Champion> yi = new MasterYi;
unique_ptr<Champion> riven = new Riven;
std::vector<std::unique_ptr<Champion> > pChampions = { new Skarner };
Hy everyone, here again. Continuing the code from my previous question : Is this a bad hack? memcpy with virtual classes
I corrected that, using the Clone approach as suggested, but I'm having an error that also happened before I tried the memcpy thing(read question above).
What I'm trying to do is to create a lambda that captures the current script and executes it, and then pass and store that lambda in an object ( Trigger*), in the member InternalCallback.
I get an access violation error on the lambda assignment: http://imgur.com/OKLMJpa
The error happens only at the 4th iteration of this code:
if(CheckHR(EnginePTR->iPhysics->CreateFromFile(physicsPath,StartingTriggerID,trans,scale,-1,false,engPtr)) == HR_Correct)
{
_Lua::ScriptedEntity * newScript = EntityBase->Clone(vm);//nullptr;
string luaPath = transforms.next_sibling().next_sibling().first_attribute().as_string();
if(UseRelativePaths)
{
stringstream temp2;
temp2 << _Core::ExePath() << LuaSubfolder << "\\" << luaPath;
luaPath = temp2.str();
}
newScript->CompileFile(luaPath.c_str());
newScript->EnginePTR_voidptr = engPtr;
auto callback = [=](_Physics::Trigger* trigger,PxTriggerPair* pairs, PxU32 count)
{
newScript->SelectScriptFunction("TriggerCallback");
newScript->AddParam(trigger->Id);
auto data = (_Physics::RayCastingStats*)pairs->otherShape->userData;
newScript->AddParam((PxU8)pairs->flags);
newScript->AddParam(data->ID);
newScript->AddParam((int)data->Type);
newScript->AddParam((int)count);
newScript->Go(1);
return;
};
((_Physics::Trigger*)EnginePTR->iPhysics->GetPhysicObject(StartingTriggerID))->InternalCallback = callback;
StartingTriggerID++;
}
This is the code for Trigger
class Trigger : public PhysicObject
{
public:
Trigger()
{
ActorDynamic = nullptr;
ActorStatic = nullptr;
InternalCallback = nullptr;
}
virtual HRESULT Update(float ElapsedTime,void * EnginePTR);
virtual HRESULT Cleanup(); // Release the actor!!
long Id;
ShapeTypes Type;
static const PhysicObjectType PhysicsType = PhysicObjectType::Trigger;
PxVec3 Scale;
void* UserData;
void Callback(PxTriggerPair* pairs,PxU32 count)
{
InternalCallback(this,pairs,count);
}
function<void(_Physics::Trigger* trigger,PxTriggerPair* pairs, PxU32 count)> InternalCallback;
};
By iteration I mean that is part of a for loop.
My system is Win 7 64 bits, Intel i3, NVIDIA GTX 480, and the compiler Visual Studio 2012 Express, using the C++11 toolset.
I'm really out of ideas. I tested for heap corruption, it appears to be good, I changed the capture in the lambda, changed nothing, I skip the 4th object and it works.
Any help would be really appreciated.
Edit: As required, here is the callstack: http://imgur.com/P7P3t4k
Solved. It was a design error. I store a lot of objects in a map, and they all derive from an object class ( like above, where Trigger derives from PhysicObject ).
The problem was that I was having IDs collisions, so the object stored in ID 5 wasn't a Trigger, so the cast created a bad object, and so the program crashed.
Silly error, really specific, but it might help somebody to remember to check temporal objects.
I have a pretty weird error while trying to implement a board game in QT. This is my second time, having the same issue, and now i think it's time to ask here.
I'm still at the game's logic part, which have a class named Field, and a class named Board. The Board class has a QVector < Field* > fields attribute, which is a vector of Field pointers. And here is the problem. I have a function which supposed to upload this vector with new Fields. Here is my source, it's pretty straight forward:
void Board::addFields()
{
for(int i = 0; i<size; i++) //the board's size is size x size
{
for(int j = 0; j<size; j++)
{
Field * f = new Field();
fields.push_back(f);
//qDebug()<<i*size+j<<" "<<f;
}
}
//qDebug()<<fields.size();
}
And after i got a ton of weird errors, i decided to write to the console the actual number of elements, the reference of the actual element, and after the two loop the size of the vector.
The result was pretty strange, i got no errors, but somtimes it added all my elements, sometimes it stopped at a random number of elements, and the size of the vector doesnt even got printed out like this:
result 1 (normal):
0 0xa173a8
...
24 0x701c18
25
result 2 (??? every time with a different number of elements):
0 0xa173a8
...
12 0xa17548
//and no vector size, i assume the function got a return; because of something
I tried it with both QVector, and std::vector, it's the same. Please if someone got any idea, what the problem could be, tell me!
Thanks, and sorry for my english!
EDIT
All my code is here:
field.h: http://paste2.org/p/1937231
field.cpp: http://paste2.org/p/1937232
player.h: http://paste2.org/p/1937238
player.cpp: http://paste2.org/p/1937239
board.h: http://paste2.org/p/1937234
board.cpp: http://paste2.org/p/1937235
main.cpp: http://paste2.org/p/1937243
Thanks Everyone for the help, i found the solution.
Since i was making the logic part of a window application, i started a QT gui project. It generated for me a main() function with this:
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
I didn't know what this is, but because i didn't need any windows for now, i removed the code, and replaced it with my code, and a simple return 0; at the end. This must have caused the problem, because when i added the QApplication to the code again:
QApplication a(argc, argv);
Board b(10);
return a.exec();
It worked like a charm...
I don't know what to do in this case, if i could, i would give the point to all of you, who tried to help. But anyways, thank you very much for the help! :)
When you type new Field(); you make a dynamic memory allocation. The returned pointer actually is quite random, and you should not rely on it to be sequential. But normally that is no problem.
And after i got a ton of weird errors, i decided to write to the console the actual number of elements, the reference of the actual element, and after the two loop the size of the vector.
What errors are you experiencing exactly?
Is size a member? for my experience if things happen randomly it's 98% caused by members not initialized..
I don't know details of object initialization in C++, but
Board::Board(int size):size(size)
{
playerOne = new Player("Player One");
playerTwo = new Player("Player Two");
newGame(this->size);
}
may be the cause of the trouble. indeed, newGame use fields which is not explicitely initialized. So try using
Board::Board(int size):size(size), fields(size*size) //or just fields()
{
...
}
And tell us what happens.