Why am I getting a race condition? - c++

I'm trying to combine multiple CGAL meshes into one single geometry.
I have the following sequential code that works perfectly fine:
while (m_toCombine.size() > 1) {
auto mesh1 = m_toCombine.front();
m_toCombine.pop_front();
auto mesh2 = m_toCombine.front();
m_toCombine.pop_front();
bool result = CGAL::Polygon_mesh_processing::corefine_and_compute_union(mesh1, mesh2, mesh2);
m_toCombine.push_back(mesh2);
}
Where m_toCombine is a std::list<Triangle_mesh_exact>.
Triangle_mesh_exact is a type of CGAL mesh (triangulated polyhedron geometry). But I don't think it's really relevant to the problem.
Unfortunately, this process is way too slow for my intended application, so I decided to use the "divide to conquer" concept and combine meshes in a parallel fashion:
class Combiner
{
public:
Combiner(const std::list<Triangle_mesh_exact>& toCombine) :
m_toCombine(toCombine) {};
~Combiner() {};
Triangle_mesh_exact combineMeshes();
void combineMeshes2();
private:
std::mutex m_listMutex, m_threadListMutex;
std::mutex m_eventLock;
std::list<MiniThread> m_threads;
std::list<Triangle_mesh_exact> m_toCombine;
std::condition_variable m_eventSignal;
std::atomic<bool> m_done = false;
//void poll(int threadListIndex);
};
Triangle_mesh_exact Combiner::combineMeshes()
{
std::unique_lock<std::mutex> uniqueLock(m_eventLock, std::defer_lock);
int runningCount = 0, finishedCount = 0;
int toCombineCount = m_toCombine.size();
bool stillRunning = false;
bool stillCombining = true;
while (stillCombining || stillRunning) {
uniqueLock.lock();
//std::lock_guard<std::mutex> lock(m_listMutex);
m_listMutex.lock();
Triangle_mesh_exact mesh1 = std::move(m_toCombine.front());
m_toCombine.pop_front();
toCombineCount--;
Triangle_mesh_exact mesh2 = std::move(m_toCombine.front());
m_toCombine.pop_front();
toCombineCount--;
m_listMutex.unlock();
runningCount++;
auto thread = new std::thread([&, this, mesh1, mesh2]() mutable {
//m_listMutex.lock();
CGAL::Polygon_mesh_processing::corefine_and_compute_union(mesh1, mesh2, mesh2);
std::lock_guard<std::mutex> lock(m_listMutex);
m_toCombine.push_back(mesh2);
toCombineCount++;
finishedCount++;
m_eventSignal.notify_one();
//m_listMutex.unlock();
});
thread->detach();
while (toCombineCount < 2 && runningCount != finishedCount) {
m_eventSignal.wait(uniqueLock);
}
stillRunning = runningCount != finishedCount;
stillCombining = toCombineCount >= 2;
uniqueLock.unlock();
}
return m_toCombine.front();
}
Unfortunately, despite being extra careful, I'm getting crashes of memory access violation or errors related to either mesh1 or mesh2 destructors.
Am I missing something?

Instead complicating things check capability of standard library:
std::reduce - cppreference.com
Triangle_mesh_exact combine(Triangle_mesh_exact& a, Triangle_mesh_exact& b)
{
auto success = CGAL::Polygon_mesh_processing::corefine_and_compute_union(a, b, b);
if (!success) throw my_combine_exception{};
return b;
}
Triangle_mesh_exact combineAll()
{
if (m_toCombine.size() == 1) return m_toCombine.front();
if (m_toCombine.empty()) throw std::invalid_argument("");
return std::reduce(std::execution::par,
m_toCombine.begin() + 1, m_toCombine.end(),
m_toCombine.front(), combine);
}

Related

I am getting a TLE error while performing cycle detection

I have written a code to the leetcode problem(courseSchedule) which basically asks whether a given set of courses can be done given dependencies. my approach is to create a graph and then check for a cycle, however, it's giving a TLE error. Can you help me as to why is the TLE happening or if there's a better approach that I can use ?
bool cycle( vector<vector<int>> &adj,int i,vector<bool> vis){
if(vis[i])
return true;
vis[i]=true;
for(int k=0;k<adj[i].size();k++)
if(cycle(adj,adj[i][k],vis))
return true;
return false;
}
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> adj(numCourses);
for(int i=0;i<prerequisites.size();i++)
adj[prerequisites[i][1]].push_back(prerequisites[i][0]);
vector<bool> vis(numCourses,false);
for(int i=0;i<numCourses;i++)
if(cycle(adj,i,vis))
return false;
return true;
}
};
Actually, your function is correct but so inefficient.
This is because in the cycle function performs so many redundant operations i.e check for the same node multiple times.
Your Code:
bool cycle( vector<vector<int>> &adj,int i,vector<bool> vis){
if(vis[i])
return true;
vis[i] = true;
for(int k = 0; k < adj[i].size(); k++)
if(cycle(adj, adj[i][k], vis))
return true;
return false;
}
Ex:
0 ---> 1 ---> 2 ......... (some more edges)
0 ---> 3 ---> 2 ---> 4 ........ (some more edges)
So, for this graph, for the start vertex 0 (with your code) for the bool function:
iteration - 1: you perform the DFS and check for 1 and 2 and
......
iteration - 2: you perform the DFS and check for 3 and again 2 .....
So, like this, you will be recomputing the same sub-problems. To avoid this you need to put another array just check if a node is already computed.
So I have introduced another vector var (initialized to false) which basically sets to true if node is visited and got approved as non-cycle node (which doesn't involve in a cycle) .
Improved Code:
bool cycle( vector<vector<int>> &adj,int i,vector<bool> vis, vector<bool>& var){
// if i involves in cycle and visited in the current sequence
if(!var[i] and vis[i])
return true;
vis[i] = true;
for(int k=0;k<adj[i].size();k++) {
// if adj[i][k] is true i.e doesn't involve in cycle, so no need to check it. If it is false we should check it.
if(!var[adj[i][k]] and cycle(adj,adj[i][k],vis, var))
return true;
else
var[adj[i][k]] = true; // else setting true to tell it doesn't involve in cycle
}
// setting true to tell it doesn't involve in cycle
var[i] = true;
return false;
}
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> adj(numCourses);
for(int i=0;i<prerequisites.size();i++)
adj[prerequisites[i][1]].push_back(prerequisites[i][0]);
vector<bool> vis(numCourses,false);
vector<bool> var(numCourses,false);
for(int i=0;i<numCourses;i++)
if(cycle(adj,i,vis, var))
return false;
return true;
}
};
Note:
I just made small changes to make your code overcome TLE without changing the basic logic. But this is still inefficient as your logic needs to pass the vector by value. I suggest you think another way :)
I also think vis is not passed by reference would be the problem for large size test cases.
This is a similar depth first search graph method, that'd pass through:
#include <cstdint>
#include <utility>
#include <vector>
const static struct Solution {
static bool canFinish(
const int num_courses,
const std::vector<std::vector<int>>& prerequisites
) {
GraphType graph = buildCourseGraph(prerequisites, num_courses);
std::vector<bool> to_take(num_courses, false);
std::vector<bool> taken(num_courses, false);
for (SizeType course = 0; course < num_courses; ++course) {
if (!taken[course] && !validateAcyclic(graph, course, to_take, taken)) {
return false;
}
}
return true;
}
private:
using GraphType = std::vector<std::vector<int>>;
using SizeType = std::uint_fast16_t;
static GraphType buildCourseGraph(
const std::vector<std::vector<int>>& prerequisites,
const SizeType num_courses
) {
GraphType graph(num_courses);
for (const auto& prerequisite : prerequisites) {
graph[prerequisite[1]].emplace_back(prerequisite[0]);
}
return graph;
}
static bool validateAcyclic(
const GraphType& graph,
const SizeType& course,
std::vector<bool>& to_take,
std::vector<bool>& taken
) {
if (to_take[course]) {
return false;
}
if (taken[course]) {
return true;
}
to_take[course] = taken[course] = true;
for (const auto& adj_course : graph[course]) {
if (!validateAcyclic(graph, adj_course, to_take, taken)) {
return false;
}
}
to_take[course] = false;
return true;
}
};
and here is LeetCode's depth first search solution in Java (with comments):
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
// course -> list of next courses
HashMap<Integer, List<Integer>> courseDict = new HashMap<>();
// build the graph first
for (int[] relation : prerequisites) {
// relation[0] depends on relation[1]
if (courseDict.containsKey(relation[1])) {
courseDict.get(relation[1]).add(relation[0]);
} else {
List<Integer> nextCourses = new LinkedList<>();
nextCourses.add(relation[0]);
courseDict.put(relation[1], nextCourses);
}
}
boolean[] checked = new boolean[numCourses];
boolean[] path = new boolean[numCourses];
for (int currCourse = 0; currCourse < numCourses; ++currCourse) {
if (this.isCyclic(currCourse, courseDict, checked, path))
return false;
}
return true;
}
/*
* postorder DFS check that no cycle would be formed starting from currCourse
*/
protected boolean isCyclic(
Integer currCourse, HashMap<Integer, List<Integer>> courseDict,
boolean[] checked, boolean[] path) {
// bottom cases
if (checked[currCourse])
// this node has been checked, no cycle would be formed with this node.
return false;
if (path[currCourse])
// come across a previously visited node, i.e. detect the cycle
return true;
// no following courses, no loop.
if (!courseDict.containsKey(currCourse))
return false;
// before backtracking, mark the node in the path
path[currCourse] = true;
boolean ret = false;
// postorder DFS, to visit all its children first.
for (Integer child : courseDict.get(currCourse)) {
ret = this.isCyclic(child, courseDict, checked, path);
if (ret)
break;
}
// after the visits of children, we come back to process the node itself
// remove the node from the path
path[currCourse] = false;
// Now that we've visited the nodes in the downstream,
// we complete the check of this node.
checked[currCourse] = true;
return ret;
}
}
References
For additional details, please see the Discussion Board which you can find plenty of well-explained accepted solutions in there, with a variety of languages including efficient algorithms and asymptotic time/space complexity analysis1, 2.

While loop - how to remove code duplication

It's not the first time I find myself in the following situation:
bool a = some_very_long_computation;
bool b = another_very_long_computation;
while (a && b) {
...
a = some_very_long_computation;
b = another_very_long_computation;
}
I don't want to compute everything in while condition, since computations are long and I want to give them appropriate names.
I don't want to create helper functions, because computation uses many local variables, and passing them all will make the code much less readable (and it will be some_huge_call).
It's unknown whether loop body will be executed at least once.
What is a good pattern in such situation? Currently I face it in C++, but I've encountered this in other languages as well. I can solve it by using additional variable isFirstPass, but it looks ugly (and, I guess, will cause some warnings):
bool a, b;
bool isFirstPass = true;
do {
if (!isFirstPass) {
...
} else {
isFirstPass = false;
}
a = some_very_long_computation;
b = another_very_long_computation;
} while (a && b);
The direct simplification of your code is:
while (
some_very_long_computation &&
another_very_long_computation
) {
...
}
If you want to keep the variables a and b:
bool a, b;
while (
(a = some_very_long_computation) &&
(b = another_very_long_computation)
) {
...
}
If you don't want to put the conditions into the while condition:
while (true) {
bool a = some_very_long_computation;
bool b = another_very_long_computation;
if (!(a && b)) {
break;
}
...
}
You could also create helper lambdas (which have access to local variables):
auto fa = [&]() { return some_very_long_computation; };
auto fb = [&]() { return another_very_long_computation; };
while (fa() && fb()) {
...
}

C++ code refactoring for if scenario

I'm looking to refactor the c++ code for if conditions which will reduce the number of lines of code as well as it should have min complexity.
Here is the example:
if (xyz->a != cmd->aa)
{
xyz->a = cmd->aa;
obj->isFound = true; //common code for all ifs
}
if (xyz->b != cmd->bb)
{
xyz->b = cmd->bb;
obj->isFound = true;
}
And so on.. Here a, b, aa, bb are defined as a struct element.
Another example having if condition with arrays:
if (abc->r16[0] != cmd->r0m)
{
abc>r16[0] = cmd->r0m;
obj->isFound = true; //some common code for all ifs
}
if (abc->r16[1] != cmd->r1m)
{
abc>r16[1] = cmd->r1m;
obj->isFound = true; //some common code for all ifs
}
And so on for r16[0] to r16[15]. Here r16[15] is defined inside struct.
Last scenario is for if condition with multidimensional array:
if (pqr->c_0_15_r_0_15[0][0] != cmd->obj0000)
{
pqr->c_0_15_r_0_15[0][0] = cmd->obj0000
obj->isFound = true; //some common code for all ifs
}
if (pqr->c_0_15_r_0_15[1][0] != cmd->obj0100)
{
pqr->c_0_15_r_0_15[1][0] = cmd->obj0100
obj->isFound = true; //some common code for all ifs
}
if (pqr->c_0_15_r_0_15[2][0] != cmd->obj0000)
{
pqr->c_0_15_r_0_15[2][0] = cmd->obj0200
obj->isFound = true; //some common code for all ifs
}
Here c_0_15_r_0_15[2][0] will go through [0][0] to [15][0] and then [0][1] to [15][1] and so on...
For all such if condition scenario there will me 100's of if statements which should be reduced. How can we refactor such code?
First, find the duplication in your code. As you already aware - the following scheme is duplicated many times:
if (a != b)
{
a = b;
found = true;
}
So - encapsulate this in a function (template if there are multiple types:
template <typename Dst, typename Src>
inline void updateIfNeeded(Dst& dst, const Src& src, bool& wasNeeded)
{
if (dst != src)
{
dst = src;
wasNeeded = true;
}
}
See - how it helps:
updateIfNeeded(abc->r16[0], cmd->r0m, obj->isFound);
updateIfNeeded(abc->r16[1], cmd->r1m, obj->isFound);
// ...
updateIfNeeded(pqr->c_0_15_r_0_15[0][0], cmd->obj0000, obj->isFound);
updateIfNeeded(pqr->c_0_15_r_0_15[1][0], cmd->obj0100, obj->isFound);
// ...
So far - reduction is quite big - and it is much more readable what is going on in this code.
What I see more - obj->isFound is repeating many times - maybe - some encapsulation in a class this time:
class Updater
{
public:
bool anyUpdateWasNeeded = false;
template <typename Dst, typename Src>
void updateIfNeeded(Dst& dst, const Src& src)
{
if (dst != src)
{
dst = src;
anyUpdateWasNeeded = true;
}
}
};
You see - not needed to pass obj->isFound so many times:
Updater upd;
upd.updateIfNeeded(abc->r16[0], cmd->r0m);
upd.updateIfNeeded(abc->r16[1], cmd->r1m);
// ...
upd.updateIfNeeded(pqr->c_0_15_r_0_15[0][0], cmd->obj0000);
upd.updateIfNeeded(pqr->c_0_15_r_0_15[1][0], cmd->obj0100);
// ...
obj->isFound = upd.anyUpdateWasNeeded;
Frankly, at this point I would consider to use preprocessor - I mean to shorten all these arrays update - this is because on left you have arrays - on right you have many fields of similar names ("indexed" names...?)
But using preprocessor is bad style - let try to update arrays with pure C++:
class Updater
{
public:
bool anyUpdateWasNeeded = false;
template <typename Dst, typename Src>
void updateIfNeeded(Dst& dst, const Src& src);
template <typename Dst, typename Src1, typename ...Src>
void updateArrayIfNeeded(Dst* dst, const Src1& src1, const Src& ...src)
{
updateIfNeeded(*dst, src1);
updateArrayIfNeeded(dst + 1, src...);
}
template <typename Dst>
void updateArrayIfNeeded(Dst* dst)
{
// nothing left
}
};
So - this is what left:
upd.updateArrayIfNeeded(abc->r16, cmd->r0m, cmd->r1m, ....);
upd.updateArrayIfNeeded(pqr->c_0_15_r_0_15[0], cmd->obj0000, cmd->obj0001, ...);
upd.updateArrayIfNeeded(pqr->c_0_15_r_0_15[1], cmd->obj0100, ...);
// ...
obj->isFound = upd.anyUpdateWasNeeded;
And so on...
You can put it in some function, for a start:
template<typename Lhs, typename Rhs>
void flagSetIfNEq(Lhs & lhs, Rhs const & rhs, bool & flag) {
if (lhs != rhs) {
lhs = rhs;
flag = true;
}
}
// call it like
flagSetIfNEq(xyz->a, uvw->aa, obj->found)!
I'm assuming that found in your code is of type bool.
Though if you have that "100s of times" in your code you probably should consider a more aggressive refactoring.
And give that function a better name.

LinearHashTable iter not dereferencable and iter not

Hy all :)
I am using 1.5.4-all (2014-10-22) in my VC++ project (Microsoft Visual C++ Compiler 18.00.21005.1 for x86 platform).
My problem is that I get the following error message after some time. The time, after which the error occurs differ quiet a lot - sometimes it happens after 30 secs and sometimes after 5 minutes.
I could locate the source for the error in the LinearHashTable.h file at line 214:
I have the following method where a Shot (struct) is added to the table:
void ShotSimulationService::SimulateShot(Shot shot) {
MutexThreadLock.lock();
shots.insert(ShotsSetType::ValueType(SimulationShot(shot)));
errorCount = 0;
MutexThreadLock.unlock();
}
The call of SimulateShot is from another thread than the handling of the following code:
void ShotSimulationService::Update(WebcamService* observable) {
if (shots.empty()) {
return;
}
try {
Mat frame = observable->GetLastImage().clone();
ShotsSetType::Iterator iter = shots.begin();
vector<Shot> deleteShots;
errorCount++;
while (iter != shots.end()){
if (iter->SimulateStartExplosion()) {
//simulate gun explosion
OverlayImage(frame, gunShotImg, iter->startPoint);
}
//simulate explosion
SimulationShot::SimulationHitStatus status = iter->status;
if (status == SimulationShot::SimulationHitStatus::UNKNOWN) {
if (detectionService.HasShotHitPlayer(frame, *iter)) {
iter->status = SimulationShot::HIT_PLAYER;
iter->SetCurrentPointAsEndoint();
//Notify that player was hit
playerHitQueue.enqueueNotification(new PlayerHitNotification(iter->hitPlayer));
}
}
if (iter->SimulateEndExplosion()) {
if (status == SimulationShot::HIT_PLAYER) {
int explosionx = iter->endPoint.x - robotExplosionHalfXSize > 0 ? iter->endPoint.x - robotExplosionHalfXSize : 0;
int explosionY = iter->endPoint.y - robotExplosionHalfYSize > 0 ? iter->endPoint.y - robotExplosionHalfYSize : 0;
OverlayImage(frame, robotExplosionImg, Point2i(explosionx, explosionY));
}
else {
// status == SimulationShot::HIT_WALL or UNKNOWN
int explosionx = iter->endPoint.x - wallExplosionHalfXSize > 0 ? iter->endPoint.x - wallExplosionHalfXSize : 0;
int explosionY = iter->endPoint.y - wallExplosionHalfYSize > 0 ? iter->endPoint.y - wallExplosionHalfYSize : 0;
OverlayImage(frame, robotExplosionImg, Point2i(explosionx, explosionY));
if (status != SimulationShot::HIT_WALL) {
iter->status = SimulationShot::HIT_WALL;
}
}
if (iter->IsSimulationFinished()) {
deleteShots.push_back(*iter);
}
}
else {
//simulate bullet
OverlayImage(frame, cheeseImg, iter->GetNextShotPoint());
}
++iter;
}
//delete finished simulations
MutexThreadLock.lock();
for each (Shot shot in deleteShots)
{
shots.erase(shot);
}
MutexThreadLock.unlock();
}
catch (cv::Exception& e) {
Logger& logger = Logger::get("Test");
logger.error(e.what());
}
}
The Update method is called quiet often - always when a new webcam frame is available.
The callstack of the error starts in the following line:
if (iter->SimulateEndExplosion()) {
In the method SimulateEndExplosion only members of the struct were used:
bool SimulateEndExplosion() {
if (status == HIT_PLAYER) {
currPercentage = 1.0;
return true;
}
if (currPercentage < 1.0) {
return false;
}
++endExplosionCtr;
return endExplosionCtr <= maxEndExplosions;
}
Does anybody have an idea why this problem occurs?
Any help and any feedback is welcome!! I have absolutly no idea what is going wrong here :(
Thanks!
Iterating in one thread and inserting in another without protecting the operations with mutex in both threads will cause this problem; when you insert, iterator will be invalidated and you will get the assertion failure. You should protect both insertion and iteration with mutex.
Also, the way you are using mutex is not safe because mutex will not be unlocked if an exception is thrown between lock() and unlock(). Use ScopedLock instead and RAII will do the job automatically and safely in all cases:
void ShotSimulationService::SimulateShot(Shot shot) {
Mutex::ScopedLock lock(MutexThreadLock);
shots.insert(ShotsSetType::ValueType(SimulationShot(shot)));
errorCount = 0;
// unlock will be called by ScopedLock destructor
}

Inherited variables are not reading correctly when using bitwise comparisons

I have a few classes set up for a game, with XMapObject as the base, and XEntity, XEnviron, and XItem inheriting it.
MapObjects have a number of flags, one of them being MAPOBJECT_SOLID. My problem is that XEntity is the only class that correctly detects MAPOBJECT_SOLID. Both Items are Environs are always considered solid by the game, regardless of the flag's state. What is important is that Environs and Item should almost never be solid.
Each class has a very basic preliminary constructor, just initializing all varibles to zero or NULL. During the CreateX() phase, Objects are linked into the map, set into a linked linked list.
Both XItem and XEnviron are a tad sloppy. They are both new, and in the middle or my debugging attempts.
Here are the relevent code samples:
XMapObject:
#define MAPOBJECT_ACTIVE 1
#define MAPOBJECT_RENDER 2
#define MAPOBJECT_SOLID 4
class XMapObject : public XObject
{
public:
Uint8 MapObjectType,Location[2],MapObjectFlags;
XMapObject *NextMapObject,*PrevMapObject;
XMapObject();
void CreateMapObject(Uint8 MapObjectType);
void SpawnMapObject(Uint8 MapObjectLocation[2]);
void RemoveMapObject();
void DeleteMapObject();
void MapObjectSetLocation(Uint8 Y,Uint8 X);
void MapObjectMapLink();
void MapObjectMapUnlink();
};
XMapObject::XMapObject()
{
MapObjectType = 0;
Location[0] = 0;
Location[1] = 1;
NextMapObject = NULL;
PrevMapObject = NULL;
}
void XMapObject::CreateMapObject(Uint8 Type)
{
MapObjectType = Type;
}
void XMapObject::SpawnMapObject(Uint8 MapObjectLocation[2])
{
if(!(MapObjectFlags & MAPOBJECT_ACTIVE)) { MapObjectFlags += MAPOBJECT_ACTIVE; }
Location[0] = MapObjectLocation[0];
Location[1] = MapObjectLocation[1];
MapObjectMapLink();
}
XEntity:
XEntity *StartEntity = NULL,*EndEntity = NULL;
class XEntity : public XMapObject
{
public:
Uint8 Health,EntityFlags;
float Speed,Time;
XEntity *NextEntity,*PrevEntity;
XItem *IventoryList;
XEntity();
void CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2]);
void DeleteEntity();
void EntityLink();
void EntityUnlink();
Uint8 MoveEntity(Uint8 YOffset,Uint8 XOffset);
};
XEntity::XEntity()
{
Health = 0;
Speed = 0;
Time = 1.0;
EntityFlags = 0;
NextEntity = NULL;
PrevEntity = NULL;
IventoryList = NULL;
}
void XEntity::CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2])
{
CreateMapObject(EntityType);
SpawnMapObject(EntityLocation);
if(!(MapObjectFlags & MAPOBJECT_SOLID) { MapObjectFlags += MAPOBJECT_SOLID; }
EntityFlags = ENTITY_CLIPPING;
Time = 1.0;
Speed = 1.0;
EntityLink();
}
void XEntity::EntityLink()
{
if(StartEntity == NULL)
{
StartEntity = this;
PrevEntity = NULL;
NextEntity = NULL;
}
else
{
EndEntity->NextEntity = this;
}
EndEntity = this;
}
XEnviron:
class XEnviron : public XMapObject
{
public:
Uint8 Effect,TimeOut;
void CreateEnviron(Uint8 Type,Uint8 Y,Uint8 X,Uint8 TimeOut);
};
void XEnviron::CreateEnviron(Uint8 EnvironType,Uint8 Y,Uint8 X,Uint8 TimeOut)
{
CreateMapObject(EnvironType);
Location[0] = Y;
Location[1] = X;
SpawnMapObject(Location);
XTile *Tile = GetTile(Y,X);
Tile->Environ = this;
MapObjectFlags = MAPOBJECT_ACTIVE + MAPOBJECT_SOLID;
printf("%i\n",MapObjectFlags);
}
XItem:
class XItem : public XMapObject
{
public:
void CreateItem(Uint8 Type,Uint8 Y,Uint8 X);
};
void XItem::CreateItem(Uint8 Type,Uint8 Y,Uint8 X)
{
CreateMapObject(Type);
Location[0] = Y;
Location[1] = X;
SpawnMapObject(Location);
}
And lastly, the entity move code. Only entities are capable of moving themselves.
Uint8 XEntity::MoveEntity(Uint8 YOffset,Uint8 XOffset)
{
Uint8
NewY = Location[0] + YOffset,
NewX = Location[1] + XOffset;
if((NewY >= 0 && NewY < MAPY) && (NewX >= 0 && NewX < MAPX))
{
XTile *Tile = GetTile(NewY,NewX);
if(Tile->MapList != NULL)
{
XMapObject *MapObject = Tile->MapList;
while(MapObject != NULL)
{
if(MapObject->MapObjectFlags & MAPOBJECT_SOLID)
{
printf("solid\n");
return 0;
}
MapObject = MapObject->NextMapObject;
}
}
if(Tile->Flags & TILE_SOLID && EntityFlags & ENTITY_CLIPPING)
{
return 0;
}
this->MapObjectSetLocation(NewY,NewX);
return 1;
}
return 0;
}
What is wierd, is that the bitwise operator always returns true when the MapObject is an Environ or an Item, but it works correctly for Entities. For debug I am using the printf "Solid", and also a printf containing the value of the flag for both Environs and Items.
Any help is greatly appreciated, as this is a major bug for the small game I am working on. I am also very new at Object Oriented programming, anything tips, suggestions and/or criticism are also welcome.
Your problem appears to be that you never initialize MapObjectFlags in any classes other than XEnviron so, as a basic type, it will have an unspecified value in XItem, XEntity and other XMapObject derived objects. I suggest that, as a member of XMapObject you explicitly initialize it to a known value.
As a rule, it is generally a good idea to ensure that all members of basic type are explicitly initialized in the initializer list of every constructor that you define.
e.g.
XMapObject()
: MapObjectFlags(0)
, // ... other initializers
{
// Other initializations
}
You can't (legally) be calling XEntity::MoveEntity on a MapObject or Environ because they don't have such a method. If you're using static_cast to change your object pointer into an XEntity so you can call MoveEntity on it, then you really have no guarantees about how the bit operation will work. In some implementations, things may appear to work in MoveEntity, but what's actually happening is it's interpreting the other object's memory as an XEntity. When it tries to access the offset where it believes MapObjectFlags exists, it's not actually there and always has that bit set to 1.
I figured out the problem earlier today - It didn't have any relation to OO programming, inheritance, or bitwise; it was a simple scope error.
The problem was in the fact that during my quick test to get an Environ in game, I declared the new variable inside of the control switch sequence, so the next time any control was used, the Environ would act in unpredictable ways.
switch(Event.key.keysym.sym)
{
...
case SDLK_c: { XEnviron Environ; Environ.InitEnviron(...); }
...
}