|
Acorn Arcade forums: Programming: Help with pointers in C++ needed!
|
Help with pointers in C++ needed! |
|
(11:48 27/11/2000) johnstlr (17:20 27/11/2000) Phlamethrower (17:44 27/11/2000) Gulli (18:29 27/11/2000) johnstlr (10:44 28/11/2000) Phlamethrower (16:50 28/11/2000) johnstlr (18:11 28/11/2000) Phlamethrower (13:58 15/6/2002)
|
|
Phlamethrower |
Message #4676, posted at 11:48, 27/11/2000 |
Unregistered user
|
OK, at the moment I'm trying to write a 3D engine in C++, so a lot of it is based around fiddling with pointers to classes. What I want to know is how to do an array of pointers to a class (which is created at run-time, so could be any size), how to read eaach item (to find out whether it points to anything), set each item, and any other important points. I already know to use -> to access members from a pointer-to-class, but I'm not quite sure how to set one pointer to class to the same value as another (would a plain = do?). Give me help or watch me go insane trying to convert it to ARM code and then debug it. |
|
[ Log in to reply ] |
|
johnstlr |
Message #4677, posted at 17:20, 27/11/2000, in reply to message #4676 |
Unregistered user
|
If I understand you right you want to do something like class CMyClass { // class definition }; then CMyClass *myClassArray[10]; to get 10 pointers to CMyClass. However, as with any C code they could be pointing at anything so doing memset(myClassArray, 0, sizeof(CMyClass *) * 10); would be good. Then you can just do if(myClassArray[2] == 0) myClassArray[2] = new CMyClass(); myClassArray[2]->myFunction(); If you want myClassArray to have dynamic size then you need to do something like the following, although I'm not sure about the syntax of new CMyClass **myClassArray; // Pointer to pointers (note plural) myClassArray = new *CMyClass[10]; and then myClassArray[2]->myFunction(); One word of advice. Although C++ is nice, if you're intending to prototype in C++ and convert wholesale to ARM then write in C. You can write in an OO style but it prevents you from using C++ structures like inheritance which are a pain in ARM unless you understand how the compiler lays classes out in memory. One possibility is to use abstract data types. Another is to create structures which include function pointers so you can then specify things like constructors and handlers etc at runtime - it's a bit more work than inheritance but not too much if you do it right. For an example of the latter you can download Warp2D - a never finished 2D game library from http://www.comp.lancs.ac.uk/computing/users/johnstlr/warp/down.html Feel free to use any of the code from there or anything else on that page if it's any use.
|
|
[ Log in to reply ] |
|
Phlamethrower |
Message #4678, posted at 17:44, 27/11/2000, in reply to message #4677 |
Unregistered user
|
Thanks. The 'CMyClass **myClassArray' is what I'm trying at the moment, the main problem is finding out whether it actually points to anything at the moment though. As for converting to ARM, this is my first attempt at a 3D engine that's likely to work, so I'm likely to rewrite it at some point anyway, probably using more ARM-friendly data structures (e.g. plain old struct's and functions), converting it file by file, routine by routine. And as to your comment about C++ being 'nice', my impressions are that it's a butt ugly language which only accepts things being done one way (e.g. having to use -> to access members of a pointer, when a plain . doesn't do anything in the first place - WHY NOT USE THAT?) Plus it's impossible to include AOF/assembler files in the source, only via the linker (and thus you have three files to contend with - headers, ARM code, and supporting C code). Plus there is the fact that it will include files twice (or at least the GNU compiler does), and only does one pass assembly (hence header files). Okay, that's enough of a rant for today. |
|
[ Log in to reply ] |
|
Gulli |
Message #4679, posted at 18:29, 27/11/2000, in reply to message #4678 |
Unregistered user
|
Thanks.And as to your comment about C++ being 'nice', my impressions are that it's a butt ugly language which only accepts things being done one way (e.g. having to use -> to access members of a pointer, when a plain . doesn't do anything in the first place - WHY NOT USE THAT?) The . actually has a similar purpose in C++, just that it's not for use with pointers: CMyClass MyClassArray; MyClassArray.size = 10; CMyClass *MyClassArray; MyClassArray->size = 10; I think I'm not typing nonsense here but if I am, someone will definately correct me. C++ is not my first language (yet) 172
|
|
[ Log in to reply ] |
|
johnstlr |
Message #4680, posted at 10:44, 28/11/2000, in reply to message #4678 |
Unregistered user
|
Thanks.The 'CMyClass **myClassArray' is what I'm trying at the moment, the main problem is finding out whether it actually points to anything at the moment though. When you declare it do CMyClass **myClassArray = 0; and if you ever delete the array set it to 0 as well afterwards. This is standard C++ practise and allows you to see if it points to something or not As for converting to ARM, this is my first attempt at a 3D engine that's likely to work, so I'm likely to rewrite it at some point anyway, probably using more ARM-friendly data structures (e.g. plain old struct's and functions), converting it file by file, routine by routine. A good idea is to get hold of a profiler and just convert where necessary. However the only one I'm aware of is HierProf that comes with Dr Smiths toolkit from WSS and I'm not sure if it supports C++. To be honest I never got the hang of it myself. I'd start with rasterisation routines and then mathematical transformation routines and these tend to be where most of your time is spent (ie look at what 3D cards offer you) And as to your comment about C++ being 'nice', my impressions are that it's a butt ugly language which only accepts things being done one way (e.g. having to use -> to access members of a pointer, when a plain . doesn't do anything in the first place - WHY NOT USE THAT?) I get the impression from this that you've either done Java or Ada programming but not much C because the use of "." and "->" makes perfect sense from a C programmers perspective. In C the "." is used to access the member field of a variable instance of a composite data structure, so you have MyStruct myStruct; myStruct.someMember whereas the "->" is used to access the member when you have a pointer reference to the structure. This behaviour is carried over to C++. The reason you don't have this dual system in Ada and Java is that in both of these languages you cannot have variable instantiations of composite data types (ie not instantiated on the stack). Everything is allocated from the heap so there's no difference. However C++ adds a spanner into the works through it's idea of references. A reference is effectively a const pointer (ie you can't change the pointer value) so you see code like void someFunc(MyStruct &myStruct) { // myStruct is a REFERENCE to a structure which means that it has been passed by // reference - any changes we make will be saved in the variable that was passed to // us. However doing something like myStruct++ is illegal myStruct.member = 1; } then elsewhere MyStruct myStruct; someFunc(myStruct); // Note the & is not need to pass as reference. Plus it's impossible to include AOF/assembler files in the source, only via the linker (and thus you have three files to contend with - headers, ARM code, and supporting C code). Plus there is the fact that it will include files twice (or at least the GNU compiler does), and only does one pass assembly (hence header files). This is a GOOD thing. It forces you to keep system specific assembly code separate from your source code thus aiding portability. I don't see why having .c .h and .s files is a burden - especially if you're using a make tool. My projects tend to have loads of files anyway as I separate code out into related functions / classes. I would certainly never dream of mixing assembly code with C++ as the two are so far apart in abstraction is doesn't make sense. Usually the ARM code is declared as "C" type functions and the C++ merely wraps it. As for including header files multiple times - all C/C++ compilers do this. This is why all header files are bracketed with something like #ifndef __myheaderfile_h #define __myheaderfile_h /* stuff goes here */ #endif The compiler will only include the header file if __myheaderfile_h is not defined, which is only true the first time it is included. This way you prevent multiple declaration errors.
|
|
[ Log in to reply ] |
|
Phlamethrower |
Message #4681, posted at 16:50, 28/11/2000, in reply to message #4680 |
Unregistered user
|
I get the impression from this that you've either done Java or Ada programming... I've never touched Java and Ada. The closest thing to C i've worked with before is Quake C, which always uses . to access members of entities
...but not much C because the use of "." and "->" makes perfect sense from a C programmers perspective. That's my entire point - do we really need two versions of what is essentially the same thing? It just complicates things, where you've got to think 'do we need a . or a ->?' each time you want to do things, not to mention the time it takes to do '->' instead of '.' Plus it's impossible to include AOF/assembler files in the source, only via the linker (and thus you have three files to contend with - headers, ARM code, and supporting C code). Plus there is the fact that it will include files twice (or at least the GNU compiler does), and only does one pass assembly (hence header files). This is a GOOD thing. It forces you to keep system specific assembly code separate from your source code thus aiding portability.
I'm not really that bothered about the seperate files, it's just that you've got to go through making sure everything is put in and in the right place, and with large projects it can get a bit out of hand.
I don't see why having .c .h and .s files is a burden - especially if you're using a make tool. Exactly! You need a make tool, therefore that's another burden! And as for portability, is everyone going to have that make tool? Will everyone have the same compiler and libraries?
My projects tend to have loads of files anyway as I separate code out into related functions / classes. I would certainly never dream of mixing assembly code with C++ as the two are so far apart in abstraction is doesn't make sense. Usually the ARM code is declared as "C" type functions and the C++ merely wraps it. True, but it's the basic fact that you've got to manage so many things that makes life difficult. Just putting all the code together and not worrying about whether functions are defined before they are called, whether you need .'s or ->'s, and other things like casts (which are a pain for new users) would make life a lot better.
As for including header files multiple times - all C/C++ compilers do this. This is why all header files are bracketed with something like#ifndef __myheaderfile_h #define __myheaderfile_h /* stuff goes here */ #endif Did I hear someone mention a burden? Having to do that at the start of every header file, as well as remembering to include the basic C/C++ header files for every program you write?
|
|
[ Log in to reply ] |
|
johnstlr |
Message #4682, posted at 18:11, 28/11/2000, in reply to message #4681 |
Unregistered user
|
I've never touched Java and Ada. The closest thing to C i've worked with before is Quake C, which always uses . to access members of entities Ahh, the light dawns. Ok QuakeC is an excellent example of what I was talking about with Java. It's a game specific language (not general purpose although Java is), it runs in a Virtual Machine and I bet it allocates everything from the heap, hence the fact that it just uses the "." operator because you can't access a structure or class through a pointer as such. That's my entire point - do we really need two versions of what is essentially the same thing? It just complicates things, where you've got to think 'do we need a . or a ->?' each time you want to do things, not to mention the time it takes to do '->' instead of '.' But they are NOT the same, not by a long shot. The crunch comes down where the variables are allocated. In C and C++ variables that are simply declared such as MyStruct myStruct are classed as automatic variables. The compiler creates them on the stack when the block of code they are declared in is entered, and removes them from the stack when the program leaves that code block. Notice that you don't have to clean up after yourself but also that the variables are temporary. Other points to note are that you incur the overhead of setting up the stack for the variables and that they are normally passed by value, which is inefficient for complex datatypes as everything gets copied. If you declare a pointer to a variable, ie MyStruct *myStruct, you have to explicitly allocate the memory for it on the heap (using malloc in C or new in C++) and you have to explicitly free it (free in C or delete in C++) when finished. If you don't free the memory you get memory leaks. A common cause of memory leaks is doing something like MyStruct *ptr1, *ptr2; ptr1 = new MyStruct; ptr1 = ptr2; // We've now lost the reference to the memory allocated with new and // have a memory leak The use of "->" makes it explicit that you have a pointer to some memory and not just an automatic variable. If you used the same notation for both it would be impossible to write programs as you would never know what you were dealing with. One caveat a variable referenced through a pointer doesn't have to be allocated on the heap, it could've been passed by reference to a function. Advantages of this approach is that it gives the programmer more control - it's much closer to assembly language and requires a smaller runtime environment. It also allows more efficient code to be written. Disadvantages are the need for two notations and the lack of garbage collection (although this can be added on top) which puts more onus on the developer. However given the choice between slightly more difficult control and no control I'd know which I'd go for everytime. I'm not really that bothered about the seperate files, it's just that you've got to go through making sure everything is put in and in the right place, and with large projects it can get a bit out of hand. Don't take this personally but just chucking everything in one file is bad for several reasons, and I'm not the only one who thinks this - look at any team based development, look at any large project on sourceforge and Java practically forces you to put seperate classes in seperate files. Some reasons are 1) Using multiple files you can break down the project into managable chunks of related classed and functions. Once the module (or class) has been created you can forget about it apart from the interface. Also if the code doesn't change much it won't have to be recompiled all the time. This can save "huge" amounts of time on large projects 2) In addition to this you're already using seperate files - what about the C libraries you link to? In QuakeC a lot of functionality comes from calling services from code in sourcefiles other than the main interpreter. 3) Team based development is impossible if there is only one source file without specialist tool support that allows you to lock parts of a source file. Even then this isn't particularly efficient. 4) You need less memory to compile a bunch of small source files than one large one. There are more but this is already getting long. Everything I have stated above is accepted good practise for software engineering on large and collaborative projects. Personally I learnt a lot of them through experience before I even started my Computer Science degree where it was ground into us for 3 years. Exactly! You need a make tool, therefore that's another burden! And as for portability, is everyone going to have that make tool? Will everyone have the same compiler and libraries? A make tool is hardly a burden. Ok if you choose to write make files yourself it can get complex but even Acorn C++ comes with a simple make tool. Visual C++ does automatic project management as well. As for the GNU tools, well they're not known for being easy to use but IDEs which automate project management are available on linux, just not RISC OS. No, people will not have the same compiler and libraries. You can only depend on people having the standard libraries - ie the ANSI libraries for C (and, slowly, C++ although the Acorn C++ compiler is well out of date). The compiler won't matter if you stick to the standard libraries and write portable code. Even make files are portable (admittedly RISC OS has fallen behind here as well although going to another platform should be straightforward) The tools themselves are irrelevant because it's the language and make files that have been standardised. True, but it's the basic fact that you've got to manage so many things that makes life difficult. Just putting all the code together and not worrying about whether functions are defined before they are called, whether you need .'s or ->'s, and other things like casts (which are a pain for new users) would make life a lot better. I can't say this enough - managing it all isn't that difficult. Spend a little time now getting to know the tools you are using - it'll pay dividends later on. Even the seemingly useless ones aren't. I used to think the Acorn tool that generates a text description of an AOF file was useless until I wanted to write a dynamic linker. As for having to understand the difference between "." and "->" and knowing about casting, a few points. Casting is a powerful tool that can be abused. Well written code shouldn't need to do much casting - especially C++ which has both static and compiler time polymorphism. However casting allows you to break the type rules of the language and sometimes it's absolutely necessary. As for the rest, well I'm going to sound a bit pompous now and I apologise, but C and C++ aren't there to molly-coddle new developers. They are serious languages designed to cope with writing large and complex programs while allowing enough control so that you can write things like operating systems and device drivers without resorting to much assembly language. I seriously doubt that any other language offers this ability without resorting to external libraries. After 7 years of developing in C and 3 in C++ I can honestly say there are a few areas of C that I still don't fully understand and that C++ still bewilders me once you get past the basics (and some not so basic stuff). Mod languages like QuakeC are powerful and easy simply because all the hard work has already been done for you. The step up from something like QuakeC to C/C++ is tricky and there is a lot to learn. All I can say is persevere - you've already seen from this forum that people are willing to help - and along the way you'll pick up a greater understanding (and perhaps appreciation) of what developers do (and then wonder why RISC OS developers do it for peanuts) Did I hear someone mention a burden? Having to do that at the start of every header file, as well as remembering to include the basic C/C++ header files for every program you write? Admittedly header files are a bit esoteric - you'll notice that something like Java doesn't use them. I believe they were originally designed to get make writing the compiler and linker a bit easier. However in just about every "proper" language you have to include extra libraries whether they be header files and libraries in C or class files in Java, as very few languages offer lots of built in support (for portability reasons). Adding the definitions to prevent multiple inclusions in C isn't a chore - you do it once and it's done. Something like Visual C++ will even do it for you.
|
|
[ Log in to reply ] |
|
Phlamethrower |
Message #4683, posted at 13:58, 15/6/2002, in reply to message #4682 |
Unregistered user
|
OK, I think I've reached the end of this argument now. As long as you realise (Or I know that you realise) that C/C++ isn't the perfect language, I'm happy. As for the . vs -> argument, I just thought that the C++ designers could have had more sense, since I always seem to use pointers a lot more often then plain pre-defined objects, and that they could let you use '.' instead of '->', unless, for example, you wanted that memory block to remain once you exit (Or have some flag included at the allocation stage, e.g. 'mystruct = new_const MyStruct;') I'm not really that bothered about the seperate files, it's just that you've got to go through making sure everything is put in and in the right place, and with large projects it can get a bit out of hand. Just me ranting on about how C is annoying, not really wanting it to look like I was saying 'put everything in one file'. I can clearly see the benefits of working with seperate files so bits of code can be worked on independently, so didn't mean to make it sound like I didn't. I should be a bit calmer on the forum now that I've had an argument with someone
|
|
[ Log in to reply ] |
|
|
Acorn Arcade forums: Programming: Help with pointers in C++ needed! | |
|