BMX to CPP
Miscellaneous Forums/General Discussion/BMX to CPP >>C++ would still be a terrible move, I think, because it would kill productivity, even after I was completely familiar with it.<<
..i really couldnt resist..yayyy :)..
..i really couldnt resist..yayyy :)..
1. You need a ";" after the closing "}" of your class declaration.
2. Your vec3 class is not going to let you access the x/y/z values because they're private by default. You can either declare them as public (add a "public:" above them) or declare it as a "struct" rather than a "class" (structs are the same as classes, except they default to public access).
3. Class declarations should go in a ".h" file, while function implementations in a ".cpp" file, which includes the ".h" file. There are reasons for this, but basically C++ library importing isn't as smart as BlitzMax / C#, so it's best to do it this way.
Here's how the above code should look, if done "properly":
File.h
The #ifdef / #define / #endif stuff is there to ensure the same file isn't included more than once (to access the code from another file, you add '#include "File.h"' to the top of the .cpp file that needs access. It's messy, and Microsoft C++ has a better way of doing it, but the above method is the only cross-platform way.
File.cpp
Yeah, learning C++ can take some time, but personally I don't think it's as hard as people make it out to be (probably because I'm so familiar with it though).
But now that I think about it, there was a time when I was totally confused and frustrated and hated C++ because I was getting strange errors all the time regarding declarations, etc., but that was because I didn't learn the proper relationship between .cpp and .h files initially.
2. Your vec3 class is not going to let you access the x/y/z values because they're private by default. You can either declare them as public (add a "public:" above them) or declare it as a "struct" rather than a "class" (structs are the same as classes, except they default to public access).
3. Class declarations should go in a ".h" file, while function implementations in a ".cpp" file, which includes the ".h" file. There are reasons for this, but basically C++ library importing isn't as smart as BlitzMax / C#, so it's best to do it this way.
Here's how the above code should look, if done "properly":
File.h
#ifndef _FILE_H__ #define _FILE_H__ struct vec3 { float x, y, z; }; class Entity { public: void SetPosition ( vec3 position, int global = 0 ); private: vec3 position; //private values aren't accessible from outside the class - the user is forced to use SetPosition() }; #endif
The #ifdef / #define / #endif stuff is there to ensure the same file isn't included more than once (to access the code from another file, you add '#include "File.h"' to the top of the .cpp file that needs access. It's messy, and Microsoft C++ has a better way of doing it, but the above method is the only cross-platform way.
File.cpp
#include "File.h" //.cpp files typically declare the actual code, while .h //files simply contain the "prototypes" of the code. It may //seem tedious to maintain two files (it can be), but it actually //has the advantage of giving you a quick overview of your //engine structure when you look at a .h header file. void Entity::SetPosition( vec3 position, int global = 0 ) { this->position = position; //no need for memcopy, C++ will optimize this to be just as efficient //however, if you absolutely must use memcpy, you can actually //overload the assignment (=) operator to use memcpy() as you like. }
>>C++ would still be a terrible move, I think, because it would kill productivity, even after I was completely familiar with it.<<
..i really couldnt resist..yayyy :)..
..i really couldnt resist..yayyy :)..
Yeah, learning C++ can take some time, but personally I don't think it's as hard as people make it out to be (probably because I'm so familiar with it though).
But now that I think about it, there was a time when I was totally confused and frustrated and hated C++ because I was getting strange errors all the time regarding declarations, etc., but that was because I didn't learn the proper relationship between .cpp and .h files initially.
Thanks.
Structures don't allow methods, though.
When I have something like this, does the vec3 object get automatically created when the entity is created?
In BMX the position is a pointer to an object, but from what I have seen, in CPP those fields are added into the class.
BMX object:
8 byte header
4 byte pointer to position object
CPP object:
4 bytes - x
4 bytes - y
4 bytes - z
Structures don't allow methods, though.
When I have something like this, does the vec3 object get automatically created when the entity is created?
class Entity { public: vec3 position;
In BMX the position is a pointer to an object, but from what I have seen, in CPP those fields are added into the class.
BMX object:
8 byte header
4 byte pointer to position object
CPP object:
4 bytes - x
4 bytes - y
4 bytes - z
Structures don't allow methods, though.
They should. What compiler are you using??
When I have something like this, does the vec3 object get automatically created when the entity is created?
Yes, all in the same block of memory. You could make it dynamically allocated if you wanted by making it a pointer to a vec3 and allocating it with the "new" command, but that would be much much less efficient.
CPP object:
4 bytes - x
4 bytes - y
4 bytes - z
4 bytes - x
4 bytes - y
4 bytes - z
Yes, that's correct, although there may be a small header if you have RTT enabled (unless it's a struct). You could even access it manually from memory like this:
Entity myEntity; float *ptr = (float*)((char*)&myEntity + headerSizeInBytes); //more reliable would be: float *ptr = (float*)&myEntity.position; float x = ptr[0]; float y = ptr[1]; float z = ptr[2];
But don't try too hard to understand that if you're not fully familiar with pointer notation and casting - I know it looks pretty cryptic :).
Anyway, C++ basically has two types of allocation - static and dynamic. Static allocation is done during compile time and doesn't take any CPU at all, while dynamic does since it need to run through memory management procedures to find an unused slot in memory.
Everything is static unless you see a "new" keyword being used or a old C "malloc()" function call. I hope this doesn't confuse you, but pointers (which are used to reference dynamically allocated data) are also statically allocated - not the data they point to, but the pointers themselves (which are 32 bits on a 32 bit OS).
I hope this makes sense. If you're not entirely sure about how something works, just let me know, and I'll try to clarify.
They should. What compiler are you using??
MSVC. I guess I was told wrong.
It makes sense to use static allocation whenever possible. That should make everything much faster.
1. What about something like a Normalize() function that returns a vec3? Is it faster to do it like this so that a new vec3 object doesn't have to be allocated?:
void Normalize( vec3 t, vec3 result ) { float m = t.Length(); result.x = t.x/m; result.y = t.y/m; result.z = t.z/m; };
2. What if I have an "aabb" struct, and I want one in the entity class? Can I call the field "aabb"?:
Class Entity { Public: aabb aabb;
It makes sense to use static allocation whenever possible. That should make everything much faster.
Exactly. Dynamic allocation can actually be a major bottleneck if you're not careful. I try to keep everything as static as possible.
What about something like a Normalize() function that returns a vec3? Is it faster to do it like this so that a new vec3 object doesn't have to be allocated?:
First, there's a mistake in that code. The "result" parameter is passed by value, so it's actually copied into the function, not referenced. To pass by reference, use the "&" symbol in the declaration (don't confuse this with the use of "&" in non-declaration lines, which gets a pointer to an object):
void Normalize( vec3 t, vec3 &result ) { float m = t.Length(); result.x = t.x/m; result.y = t.y/m; result.z = t.z/m; }
Even better would be:
inline void Normalize( const vec3 &t, vec3 &result ) { float m = t.Length(); result.x = t.x/m; result.y = t.y/m; result.z = t.z/m; }
This way the compiler knows your not modifying "t", and passes it by reference. Specifying variables as "const" is always a good idea because it gives the compiler more room for optimization.
Also remember to mark small, short functions like this as inline. This way the compiler will "copy and paste" so it's not actually calling a function at all.
2. What if I have an "aabb" struct, and I want one in the entity class? Can I call the field "aabb"?:
I think so, but I'm not sure. As a rule, class/struct names in my code are always capitalized, while variables generally are not. For example, I'd do: "AABB aabb;", so it's never been an issue for me.
P.S. You don't need a ";" after the closing brace ("}") of functions. Only for classes and structs. It's one of C++'s quirks, but fortunately classes and structs are the only place where you need the ";". There is a reason why they did this though, which I could explain (although I disagree with the reason).
Pretty cool stuff.
I wonder why they use "vec3" in GLSL and not "Vec3"?
Thanks for your advice.
I wonder why they use "vec3" in GLSL and not "Vec3"?
Thanks for your advice.
I wonder why they use "vec3" in GLSL and not "Vec3"?
There are so many different coding conventions used, and obviously different people have different preferences (although usually non-indie projects have a set style that everyone must adhere to).
GLSL probably uses "vec3" because the primitive C data types (int, float, double, bool, char, etc.) are all lower case, and they're making a point that "vec3" is a primitive data type, rather than a struct (primitive meaning it's directly supported by the hardware).
Personally, I think all datatypes should be capitalized for the reasons mentioned above, but I guess not everyone agrees. Most modern, well designed, well structured C++ libraries I've used though do use very logical techniques.
It's primarily for readability. Mostly what you'll see is:
iLikeThisFunction()
{
variableA = 1;
variableB = 2;
}
Everyone's got different conventions. Personally, I like to see everything like that whether it's a function, method, member, variable, whatever ... it's just easy to decipher the code quickly. I really hate underscores and using this method alleviates the need to separate words with extraneous characters.
iLikeThisFunction()
{
variableA = 1;
variableB = 2;
}
Everyone's got different conventions. Personally, I like to see everything like that whether it's a function, method, member, variable, whatever ... it's just easy to decipher the code quickly. I really hate underscores and using this method alleviates the need to separate words with extraneous characters.
Personally, I like to see everything like that whether it's a function, method, member, variable, whatever ... it's just easy to decipher the code quickly. I really hate underscores and using this method alleviates the need to separate words with extraneous characters.
Me too, except I like custom type definitions (classes/structs/typedefs/enums) and namespaces to be capitalized. Then it's easy to tell what's a variable and what's a type.
There are also different styles for the braces. Some people prefer this:
blahblahblah { code }
While others prefer this:
blahblahblah { code }
I just mix them based on whatever's more convenient. Over time you learn what works best for easy copy-and-paste, easy reading, etc.
Some people even do this:
blahblahblah { code }
... but I hate that, personally.
How about putting objects into an arbitrary list? I don't like building in linked list behavior in my classes, i.e. nextEntity, prevEntity. Is there anything like a ForEach loop?
What about binary trees, like BMX's TMap class?
What about binary trees, like BMX's TMap class?
Whats your engine written in then if its not C++?
I am currently looking at c#.net through MONO which looks really promising from what i have read. In theory it should mean my stuff runs on anything (linux mac windows).
No idea what C# is like to use as a language at a proper dev level though but i can read it from my general experience and i have only compiled my first few experiments. Its certainly 'nicer' than C++. (although i doubt its anywhere near as fast)
I am currently looking at c#.net through MONO which looks really promising from what i have read. In theory it should mean my stuff runs on anything (linux mac windows).
No idea what C# is like to use as a language at a proper dev level though but i can read it from my general experience and i have only compiled my first few experiments. Its certainly 'nicer' than C++. (although i doubt its anywhere near as fast)
(although i doubt its anywhere near as fast)
I read somewhere that C# is just as fast as C++..
I read somewhere that C# is just as fast as C++..
Ohpe, here we go...get your seat belts on, this topics going for a debate ride.
But on a related note, is your engine geared towards windows only? If you just went with C#, would you not be able to focus better on a single audience and speed through development, instead of trying to maintain it for multiple platforms, and not have to provide opengl support that will end up making cancer seem pleasant?
You seem to have something good going here, along with testosterone filled motivation on top. Would hate to see it become abandoned or, Mark-Siblified over c++. It just seems like everyone who goes down the c++ route indie-wise, seem to lose motivation in the end from slow results. (are you a team? or is it just you mainly working on the engine?)
Do what you gotta do though. Clearly blitzmax doesn't hold a promising feature/future for your engine.
I prefer C++ TBH its flexible for loads of stuff, good luck with it Josh :).
Its a really good system where you can have total control of the computer or as much control as you require :)
Its a really good system where you can have total control of the computer or as much control as you require :)
LarsG & Retimer: There's actually no debate - C++ is much faster than C#, at least on Windows using Microsoft's compilers. The only benchmarks I've seen where C# comes close to C++ (and surpasses it only in a few areas) are when using Microsoft Visual C# vs. GCC C++. GCC C++ is relatively slow on Windows PCs compared to Visual C++, but don't ask me why.
C++ has a few standard list classes, including binary trees, hashmaps, sets, etc., and if you don't like them you can always make your own.
I'll try to explain the basics of how the C++ STL library works with an example of using "list" (linked list), but remember that you can always use another library or even make your own linked list implementation class if you don't like this way:
However, there are a few advanced C++ features that you need to understand to be able to use the STL list commands.
- The "for" command isn't limited to numbers or anything - it's basically a initialization statement (like "i = 0;" or in this case "i = entityList.begin();"), followed by a condition that must be met to continue the loop ("i != entityList.end()" in this case), followed by the loop iterator command (++i).
- "list<Entity*> entityList;" uses the "list" class to declare "entityList", for a list of "Entity*" items (pointers to entities). The "<Entity*>" notation is actually how C++ templates work, which is a whole other area you can learn about, but for now just think of it as a sort of static compile-time parameter.
- "list<Entity*>::iterator" is declaring an iterator for the list type above. The iterator class also uses templates, so it needs the <Entity*> information as well. An "iterator" is basically a reference to some item in the list, which can be used to iterate over them (go forward, go backward).
- The iterator class here has overloaded several operators, like the "*" and "++". Calling "++i" will increment the iterator to point to the next item in the list. "*i" will return the original object added to the list (in this case, an "Entity*" (pointer to an entity).
Some other container classes (in addition to "list" [linked list]) are "vector" (dynamically resized array), "map" (binary tree), and "hash_map" (hash map), although hash_map isn't available on all platforms without additional libraries I think.
But again, you may not have learned a lot of the features the STL container classes use, so if there's something you don't understand just wait until you do before trying to use them too much.
Also, in case you haven't learned it yet, here's the difference between "++value" and "value++":
- "++value" increments the value first, then evaluates the expression if necessary. So if you did "x = ++value;", value would first be incremented, then assigned to x. If you did "x = value++;", value will first be assigned to "x" , then incremented.
- "++value" is actually (potentially) faster than "value++", but the optimizer shouldn't let this happen most of the time, although it's still good practice. The reason for this is "x = value++;" might be translated into "temp = value; ++value; x = temp;" for overloaded operators like an iterator.
How about putting objects into an arbitrary list? I don't like building in linked list behavior in my classes, i.e. nextEntity, prevEntity. Is there anything like a ForEach loop?
What about binary trees, like BMX's TMap class?
What about binary trees, like BMX's TMap class?
C++ has a few standard list classes, including binary trees, hashmaps, sets, etc., and if you don't like them you can always make your own.
I'll try to explain the basics of how the C++ STL library works with an example of using "list" (linked list), but remember that you can always use another library or even make your own linked list implementation class if you don't like this way:
#include <list> using namespace std; Entity *myEntity = new Entity(); list<Entity*> entityList; entityList.push_back(myEntity); //adds to the end of the list list<Entity*>::iterator i; for (i = entityList.begin(); i != entityList.end(); ++i) { Entity *ent = *i; ent.render(); } list<Entity*>::iterator i; for (i = entityList.begin(); i != entityList.end(); ++i) { Entity *ent = *i; delete ent; } entityList.clear();
However, there are a few advanced C++ features that you need to understand to be able to use the STL list commands.
- The "for" command isn't limited to numbers or anything - it's basically a initialization statement (like "i = 0;" or in this case "i = entityList.begin();"), followed by a condition that must be met to continue the loop ("i != entityList.end()" in this case), followed by the loop iterator command (++i).
- "list<Entity*> entityList;" uses the "list" class to declare "entityList", for a list of "Entity*" items (pointers to entities). The "<Entity*>" notation is actually how C++ templates work, which is a whole other area you can learn about, but for now just think of it as a sort of static compile-time parameter.
- "list<Entity*>::iterator" is declaring an iterator for the list type above. The iterator class also uses templates, so it needs the <Entity*> information as well. An "iterator" is basically a reference to some item in the list, which can be used to iterate over them (go forward, go backward).
- The iterator class here has overloaded several operators, like the "*" and "++". Calling "++i" will increment the iterator to point to the next item in the list. "*i" will return the original object added to the list (in this case, an "Entity*" (pointer to an entity).
Some other container classes (in addition to "list" [linked list]) are "vector" (dynamically resized array), "map" (binary tree), and "hash_map" (hash map), although hash_map isn't available on all platforms without additional libraries I think.
But again, you may not have learned a lot of the features the STL container classes use, so if there's something you don't understand just wait until you do before trying to use them too much.
Also, in case you haven't learned it yet, here's the difference between "++value" and "value++":
- "++value" increments the value first, then evaluates the expression if necessary. So if you did "x = ++value;", value would first be incremented, then assigned to x. If you did "x = value++;", value will first be assigned to "x" , then incremented.
- "++value" is actually (potentially) faster than "value++", but the optimizer shouldn't let this happen most of the time, although it's still good practice. The reason for this is "x = value++;" might be translated into "temp = value; ++value; x = temp;" for overloaded operators like an iterator.
I'm using BMX for the engine right now. I don't have any plans to change that soon, but I also intend to start researching other languages and APIs over the next six months.
I think one of the reasons BMX is considered easier is because people rely on BRL's built-in functionality. But I usually write all my own stuff anyways, so there isn't much difference between BMX and CPP. For me the main advantage of BMX is simpler syntax. BMX statements usually require about half as many characters as CPP, and I like to switch the code around a lot and experiment with different techniques.
However, BMX is poorly supported, unknown, usually confused with Dark Basic, and there is no public roadmap for the future. Mark Sibly could be dead right now, for all I know.
The single biggest motivation for me is multi-core programming. This isn't a fad that is going to go away. Right now, we could be harnessing nearly twice or even four times the CPU power, for certain tasks that can be parallelized, particularly the CPU-side of the renderer, where the visible objects are just determined and copied into an array. All we have heard from Mark on this subject is "it's hard to implement that", about a year ago. I don't like BRL's behavior, and I don't believe in them anymore. I am not going to learn another kiddie language, so C# is out.
Regarding Max3D, I come from a potentially biased viewpoint, but it seems like such a waste of time. Some of Mark's ideas are very backwards. He's talking about stencil shadows on the CPU. Okay, if you really want stencil shadows, you can get them for nearly free by using a geometry shader. But why would you use stencil shadows in 2008-2009? He's probably going about this with an additive blend approach, where he renders each light in a separate pass, since it sounds like he is trying to combine shadowmaps and stencil shadows. That is one of the worst approaches you can take. The only good way to do lighting is a deferred approach, but I don't think he has an understanding of 3D engine architecture because he has never messed around with high-end engines. So another mediocre 3D product comes to the market, and in the meantime the (potentially) greatest programming language of all time gets neglected.
So I will mess around with CPP and see what I can learn. It doesn't change anything for our engine, unless I decide at some point that I could convert the source in a week. So I am just learning how to get my regular BMX functionality out of CPP. It is possible version 2.2 could be released using CPP, but I am not going down that road until I am sure it can be easily done. Thus, I am starting my research well ahead of any plans to actually use CPP for anything.
I think one of the reasons BMX is considered easier is because people rely on BRL's built-in functionality. But I usually write all my own stuff anyways, so there isn't much difference between BMX and CPP. For me the main advantage of BMX is simpler syntax. BMX statements usually require about half as many characters as CPP, and I like to switch the code around a lot and experiment with different techniques.
However, BMX is poorly supported, unknown, usually confused with Dark Basic, and there is no public roadmap for the future. Mark Sibly could be dead right now, for all I know.
The single biggest motivation for me is multi-core programming. This isn't a fad that is going to go away. Right now, we could be harnessing nearly twice or even four times the CPU power, for certain tasks that can be parallelized, particularly the CPU-side of the renderer, where the visible objects are just determined and copied into an array. All we have heard from Mark on this subject is "it's hard to implement that", about a year ago. I don't like BRL's behavior, and I don't believe in them anymore. I am not going to learn another kiddie language, so C# is out.
Regarding Max3D, I come from a potentially biased viewpoint, but it seems like such a waste of time. Some of Mark's ideas are very backwards. He's talking about stencil shadows on the CPU. Okay, if you really want stencil shadows, you can get them for nearly free by using a geometry shader. But why would you use stencil shadows in 2008-2009? He's probably going about this with an additive blend approach, where he renders each light in a separate pass, since it sounds like he is trying to combine shadowmaps and stencil shadows. That is one of the worst approaches you can take. The only good way to do lighting is a deferred approach, but I don't think he has an understanding of 3D engine architecture because he has never messed around with high-end engines. So another mediocre 3D product comes to the market, and in the meantime the (potentially) greatest programming language of all time gets neglected.
So I will mess around with CPP and see what I can learn. It doesn't change anything for our engine, unless I decide at some point that I could convert the source in a week. So I am just learning how to get my regular BMX functionality out of CPP. It is possible version 2.2 could be released using CPP, but I am not going down that road until I am sure it can be easily done. Thus, I am starting my research well ahead of any plans to actually use CPP for anything.
I prefer C++ TBH its flexible for loads of stuff, good luck with it Josh :).
Definitely, but the main issue is supporting additional operating systems and opengl when, if focusing on one thing (limited by c#), you could get much farther ahead in the game.
I wouldn't go as far as to say that C# speeds would truly affect his engine. His engine is based on the future and he has multithreading in mind.
Thus, I am starting my research well ahead of any plans to actually use CPP for anything.
That's good news. I look forward to your updates here, as there really isn't any other products on these forums that keep going like yours.
However, BMX is poorly supported, unknown, usually confused with Dark Basic, and there is no public roadmap for the future. Mark Sibly could be dead right now, for all I know.
I think this is the crux of the problem with Blitz, there isnt enough input from the powers that be. BRL isnt just one person there are loads of people that make it up surely one of them could post on the forum about whats going on.
I have to say this Lee Bamber posts waaaay more on the Dark Basic forum and gets more feedback and information from users cause of it making it a better product im a load of ways.
Fred who makes PureBasic also appears on the forums from time to time and takes onboard information and if its not good to add it then he will tell you why and explain, yes I dont think mark should explain everything but it would be nice to know that the idea has at least been given merit.
For me it seems that Mark has let Blitz slip out of his grasp again (Amiga Blitz was the last one), maybe its time to wait for PC's to die out and then write Blitz on the next one eh Mark? For me it seems that everything that gets added is usually too little to late.
Just wanted to point out one clarification on memory allocatons as there where some slightly misleading statments.
Dynamic Allocations or Heap allocation is mangaged via the new/delete key words.
float* array= new float[12];
delete array[];
Slow Slow Slow, exactly why Garbage collected languages suck for high performance applications as they try to manage it for you. Much better managed by programmer. Dont get me wrong if you have a low performance buisness application GC rocks.
Stack
Stack allocation is when you have a function/method and you declare a variable. ie.
int foo()
{
int x;
vec3 v = {1.0,2.0,3.0};
...
}
These allocations are part of the stack frame and allocated upon entry into the function and cleaned up upon return. See Calling Conventions to understand what this stuff is about extern "C" extern "Win32" in BMAX world. Way faster than Dynamic
Static
This is using special keyword "static"
static int X;
static vec V;
This is allocated as part of the applications data segment and kinda like a global variable but can be scoped in a function like
void foo()
{
static int x;
}
Not necessarily s fast as one might believe but far faster than dynamic. Never ever used with out locking in multithread applications. In fact the above function foo is not reentrant and you will experience bad bad bugs if you either recurse or if two threads invoked.
Hope this clarifies the proper terminology for the various forms of memory allocations in modern structured languages.
BlitzMax actually supports all 3 except objects can only live on the heap, so for static or stack you only have integral data types such as ints,float,byte,double. arrays, strings or any type is an object and lives on the heap to be swept by the GC.
As for the topic, Josh learn C++ your skill and ability to produce the Leadworks engine in BlitzMax is amazing and is much harder than grasping concepts of C++. And dont buy into the crap C++ is hard dead language. Its not going anyware anytime soon in the Game or systems programming industry.
One final thing in C++ and multi-threaded applications.
Look up keyword "volatile" will save lot of grief in multi-thread C++ applications.
Doug Stastny
Dynamic Allocations or Heap allocation is mangaged via the new/delete key words.
float* array= new float[12];
delete array[];
Slow Slow Slow, exactly why Garbage collected languages suck for high performance applications as they try to manage it for you. Much better managed by programmer. Dont get me wrong if you have a low performance buisness application GC rocks.
Stack
Stack allocation is when you have a function/method and you declare a variable. ie.
int foo()
{
int x;
vec3 v = {1.0,2.0,3.0};
...
}
These allocations are part of the stack frame and allocated upon entry into the function and cleaned up upon return. See Calling Conventions to understand what this stuff is about extern "C" extern "Win32" in BMAX world. Way faster than Dynamic
Static
This is using special keyword "static"
static int X;
static vec V;
This is allocated as part of the applications data segment and kinda like a global variable but can be scoped in a function like
void foo()
{
static int x;
}
Not necessarily s fast as one might believe but far faster than dynamic. Never ever used with out locking in multithread applications. In fact the above function foo is not reentrant and you will experience bad bad bugs if you either recurse or if two threads invoked.
Hope this clarifies the proper terminology for the various forms of memory allocations in modern structured languages.
BlitzMax actually supports all 3 except objects can only live on the heap, so for static or stack you only have integral data types such as ints,float,byte,double. arrays, strings or any type is an object and lives on the heap to be swept by the GC.
As for the topic, Josh learn C++ your skill and ability to produce the Leadworks engine in BlitzMax is amazing and is much harder than grasping concepts of C++. And dont buy into the crap C++ is hard dead language. Its not going anyware anytime soon in the Game or systems programming industry.
One final thing in C++ and multi-threaded applications.
Look up keyword "volatile" will save lot of grief in multi-thread C++ applications.
Doug Stastny
I have to say this Lee Bamber posts waaaay more on the Dark Basic forum and gets more feedback and information from users cause of it making it a better product im a load of ways.
Now that we're on this topic: The OGRE engine (which is a free 3D graphics library that I use) has 10x better support than BRL - updates are posted periodically by the lead developer, and in addition to users / OGRE contributors answering questions promptly and comprehensively, etc., the main developer himself (Steve Streeting) will almost always help you out with a problem personally if necessary, or if the problem even remotely could be from a bug in the engine (he makes 10.25 posts per day on average). On top of all that, it's a free library and anything you get is purely donated time and effort!
Compare the support from a free library to BRL's support of products you pay for, and you'll see why I (and many, many others) have lost faith in BRL.
What is the equivalent in CPP to a link object?
Here is my entity constructor and destructor. You can see when it is created it gets added to the world entities list. How can I remove it from the list upon deletion?:
This is the BMX equivalent:
Here is my entity constructor and destructor. You can see when it is created it gets added to the world entities list. How can I remove it from the list upon deletion?:
Entity::Entity() { pWorld = World::current(); pWorld->entities.push_front( this ); } void ~Entity() { pWorld = null; }
This is the BMX equivalent:
Method New() world=TWorld.Current() link=world.entities.addfirst(self) EndMethod Method Free() world=Null link.Remove() EndMethod
Budman: Thanks for clarifying the stack vs. pure static data.
BTW, when I say anything that's not allocated by "new" or "malloc()" is basically static data, I mean it doesn't require a separate allocation. In a game, most everything is going to be dynamically allocated at some point (your entities, for example), so what matters is how many heap allocations it takes when loading a new entity, for example. By using all non-dynamic variables, you can reduce it to 1 (and you can actually reduce the number of allocations below 1 per object if you implement some sort of pooling strategy).
I don't know what a link object is, but based on your code I think the equivalent is an iterator:
I didn't try running this, but hopefully it doesn't have any errors. Note: There may be a better way to do this, but I'm not sure. Personally I think they should have made it so push_front() returns an iterator at the newly added item.
BTW, when I say anything that's not allocated by "new" or "malloc()" is basically static data, I mean it doesn't require a separate allocation. In a game, most everything is going to be dynamically allocated at some point (your entities, for example), so what matters is how many heap allocations it takes when loading a new entity, for example. By using all non-dynamic variables, you can reduce it to 1 (and you can actually reduce the number of allocations below 1 per object if you implement some sort of pooling strategy).
What is the equivalent in CPP to a link object?
Here is my entity constructor and destructor. You can see when it is created it gets added to the world entities list. How can I remove it from the list upon deletion?:
Here is my entity constructor and destructor. You can see when it is created it gets added to the world entities list. How can I remove it from the list upon deletion?:
I don't know what a link object is, but based on your code I think the equivalent is an iterator:
class Entity { public: Entity(); ~Entity(); private: list<Entity*>::iterator link; }; Entity::Entity() { pWorld = World::current(); pWorld->entities.push_front( this ); link = pWorld->entities.begin(); //returns an iterator at the newly added item } void ~Entity() { pWorld->entities.erase(link); pWorld = null; }
I didn't try running this, but hopefully it doesn't have any errors. Note: There may be a better way to do this, but I'm not sure. Personally I think they should have made it so push_front() returns an iterator at the newly added item.
list::remove ?
http://www.cplusplus.com/reference/stl/list/
*EDIT* Dunno, I tend use vector instead of list.
http://www.cplusplus.com/reference/stl/list/
*EDIT* Dunno, I tend use vector instead of list.
REDi: list::remove() is slow - it searches for a list item with a certain value, then deletes it. list::erase() allows you to supply an iterator which references an item and delete the item instantly.
Vectors are arrays, so they won't be good at inserting and deleting lots of items. When you remove something, the memory block has to be copied.
The Erase() method is what I was looking for. I'm not clear on how the iterator parameter works, though?
The Erase() method is what I was looking for. I'm not clear on how the iterator parameter works, though?
class Entity { public: World* pWorld; Iterator* link; Entity::Entity() { pWorld = World::current(); pWorld->entities.push_front( this ); } void ~Entity() { pWorld->entities.erase( link? ); pWorld = null; delete link; }
John, wont that link always be to the first element in the list?
*EDIT* forget that I'm an idiot ;)
*EDIT* forget that I'm an idiot ;)
Vectors are arrays, so they won't be good at inserting and deleting lots of items. When you remove something, the memory block has to be copied.
True, but you can always copy the end item into the one you're deleting and remove the end item at no cost, if you don't need the item order to be preserved. Although it's a little messy to do this with std::vector (they should have added this feature built in). Personally I'm not a huge fan of the standard vector/list/etc. functions but they do work well (and fast), and aren't annoying too often.
But typically, std::vector is used as a faster alternate to std::list when a lot of push_back() insertions are made (inserting anywhere else but the end of an array is slow obviously), while no removals are needed until the entire list can be cleared.
The Erase() method is what I was looking for. I'm not clear on how the iterator parameter works, though?
Like you say, list::erase() is what you're looking for, but I think you just need to understand what an iterator is.
A STL iterator is simply a class or struct (probably similar to BlitzMax's link class) who's purpose is to reference some item within one of your STL lists. In this case, you have a list of entities, declared like this:
list<Entity*> myList;
To be able to remove items from the list efficiently with the erase() method, you need a way of telling it which item to delete, obviously. Just like BlitzMax's link object, the list::iterator class serves the purpose of holding a link to a certain list item, so you can delete it instantly. Declaring a list iterator works like this:
list<Entity*>::iterator myIterator;
Basically, you just copy and paste what your list was declared as ("list<Entity*>" here) and add "::iterator" on the end.
When you add the "::iterator", it's defining an iterator class, not a list class. The reason you have to access the "iterator" class like this is because the "iterator" class is defined inside their "list" class (a nested class definition). There are a few advantages to using nested class definitions where logical, but that's not important right now as long as you know how to use it.
Once you declared the iterator variable, all you need to do is link it to your entity's list item when it's created, and use it to delete it when it's being deleted.
Assigning the iterator to the newly added list item is done like this:
pWorld->entities.push_front( this ); myIterator = pWorld->entities.begin();
I think you already understand what the first line does (it adds a pointer to your new entity to the list). The second line simply gets an iterator to the list item you just added, and stores it in your iterator variable.
To delete the item from the list, you supply the iterator your stored early to the erase() function and it will delete the appropriate list item:
pWorld->entities.erase(myIterator);
BTW, when defining lists and using iterators, etc., retyping "list<Entity*>" over and over again can get annoying. When I frequently use a certain type of list, it's best to typedef it to a more handy name. For example:
typedef list<Entity*> EntityList; EntityList myList; EntityList::iterator myListIterator;
Okay, so it would look like this?:
class Entity { public: World* pWorld; list<Entity*>::iterator worldLink; Entity::Entity() { pWorld = World::current(); pWorld->entities.push_front( this ); worldLink = pWorld->entities.begin(); } void ~Entity() { pWorld->entities.erase( worldLink ); delete worldLink;// Is this necessary? }
That's correct except for the "delete worldLink;" You should never "delete" anything you didn't "new", basically. "worldLink" is a part of your Entity's block in memory, so it will be deleted along with the Entity it belongs to when it is deleted.
Also, "delete worldLink;" is invalid code - you have to provide a pointer to an object when deleting that object. And even if you got a pointer to worldLink in this case, it would crash because like I said above you can't "delete" something that you didn't "new".
Also, "delete worldLink;" is invalid code - you have to provide a pointer to an object when deleting that object. And even if you got a pointer to worldLink in this case, it would crash because like I said above you can't "delete" something that you didn't "new".
I guess I don't understand what is happening here then:
worldLink = pWorld->entities.begin();
worldLink = pWorld->entities.begin();
Calling "pWorld->entities.begin()" returns an iterator object that references the first list item (which is the one that was just added). It doesn't return a pointer to the iterator, it returns the iterator by value, so it's copied into your "worldLink" variable. Remembers that iterators aren't pointers by themselves, but they act somewhat like them.
I can understand why this would be confusing. Like I said earlier, the STL container classes use a lot of advanced C++ features, and I can imagine that it would be extremely confusing to learn them all at once. And I'm probably not explaining it very well.
Your best bet would be to read through a C++ tutorial and learn things properly (although I'm still happy to answer whatever questions you may have).
I can understand why this would be confusing. Like I said earlier, the STL container classes use a lot of advanced C++ features, and I can imagine that it would be extremely confusing to learn them all at once. And I'm probably not explaining it very well.
Your best bet would be to read through a C++ tutorial and learn things properly (although I'm still happy to answer whatever questions you may have).
However, BMX is poorly supported, unknown, usually confused with Dark Basic, and there is no public roadmap for the future. Mark Sibly could be dead right now, for all I know.
That comment was so cold I had to go put on a woolly jumper.