Wolfenclone

The Partridge Family were neither partridges nor a family. Discuss.
albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Wolfenclone

Post by albinopapa » August 28th, 2018, 8:01 pm

Wow, so many questions lol.

Where do you start and stop with using pointer?
For polymorphism, you do need to use pointers or references, for a container like the unordered_map or vector, you want to use pointers, but can pass by reference to base class to functions.
For objects too large to fit on stack, you want to use pointers or at least smart pointers.
For nullability you want to use pointers.

Keep everything stack based until a member of a member... is heavyweight enough to warrant pointing to it on the heap?
Yeah, pretty much. If all your objects fit on the stack, why not use the faster stack access. For things that won't fit on stack, allocate on heap, the pointer to the heap address will be stored on the stack.

Point at your top level object on the heap and leave all its members and their members... as not pointers?
This one stuck out to me, if your object stores other objects by value and you allocate that object on the heap, the entire object and all owned objects are put on the heap.

Code: Select all

struct MyLargeStruct
{
     class TextFormatter
     {
          std::string GetLine( int _lineNumber )const;
          float lineWidth;
          
     };

     char longText[100000]; // 100KB
     int lotsOfFlags[100000]; // 400KB
     float fontSize = 16.f;
     TextFormatter formatter;
};
Just two instances of this class would fill up the stack, so you put in in heap memory, guess what, it's all on the heap.
To access the formatter: 
auto thing = std::make_unique<MyLargeStruct>();
const auto lin23 = thing->formatter.GetLine( 23 );
The point I want to make is the top level object being allocated on the heap makes all owned data stored on the heap as well, so no need to also make members pointers also.

Some combination of both?
For very large or polymophic data, you will have to use pointers, otherwise why bother with extra allocations.

Does it depend on your application or style preference?
It's your program, do as you wish.

I can see plus and minus going either way, mainly if you use something that you built to be on the heap directly on the stack will it cause problems?
The wording is a little hard to follow, but you can't store something on the stack that is too large, and that's the only thing I can think of that would specifically be designed to be stored in heap memory.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Wolfenclone

Post by albinopapa » August 28th, 2018, 8:07 pm

SSO stands for "Small String Optimization" by the way, I don't think chili was prolonging a "so". :)

Some people also make their own short vectors where if the number of elements is less than some count thresh hold or the size of all elements is less than some byte count thresh hold, then it's implemented using a stack based array, otherwise, it's allocated on the heap. Look up EASTL ( EA Standard Template Library ), I think they have one implemented.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Wolfenclone

Post by albinopapa » August 28th, 2018, 8:20 pm

I don't want to confuse the situation about using pointers to objects vs objects. Polymorphism is definitely a reason to use pointers especially if you want to store an array of different types. I think what I'm getting at is using the stack is okay for most things and heap allocation should be used sparingly. If it's unavoidable, then it's unavoidable. If it causes difficulties in maintainability using the stack then by all means, use heap allocation. I just think there are times where people tend to want to allocate on the heap BECAUSE they fear running out of stack space or because they come from a language where almost everything is allocated on the heap ( C#: new this, new that { damn it's so frustrating lol} ). Hell, even C programmers tend to allocate everything on the heap and just make the f'ing pointer global or some BS.


OFF-TOPIC:
I spent some time last summer doing a little C programming, converting the Chili framework to C. I hated every minute of it, but was still able to accomplish most of the project with little to no heap allocation. Since there are no references in C, there was a lot of passing: &gfx or &theGame; around though. I suppose this is why they allocate on the heap, to avoid this particular pain.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Firepath
Posts: 77
Joined: March 10th, 2018, 11:53 pm

Re: Wolfenclone

Post by Firepath » August 28th, 2018, 9:25 pm

chili wrote:There is no if they think about it, all containers except std::array store on the heap. std::string has a special case for very short strings where it can store on the stack for them. (sso)
OK cool, I watched a few vids on allocators(? I think) a while ago and one on Facebook's string and small string optimization and wondering if other containers do similar things. Too many unconcreted half informations swirling around in my noggin. I need to learn more.

Firepath
Posts: 77
Joined: March 10th, 2018, 11:53 pm

Re: Wolfenclone

Post by Firepath » August 28th, 2018, 9:43 pm

chili wrote:There is no if they think about it, all containers except std::array store on the heap. std::string has a special case for very short strings where it can store on the stack for them. (sso)
OK cool, I watched a few vids on allocators(? I think) a while ago and one on Facebook's string and small string optimization and wondering if other containers do similar things. Too many unconcreted half informations swirling around in my noggin. I need to learn more.

And wow thanks albinopapa I didn't expect answers to my slew of questions there, just sort of illustrating how I don't have a real handle from any angle to know what is best. You're certainly helping guys!

What I was getting at with using the class designed for the heap but then using it on the stack is that you intended initially to have a pointer to it and all its members and their members are not pointers and it is heavy. At some point you then use it (in an array maybe?) temporarily without a pointer and boom all of that suddenly it is all on the stack. Maybe I'm just freaking out over nothing.

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Wolfenclone

Post by albinopapa » August 28th, 2018, 11:15 pm

Ok, then I believe I addressed that concern. If it's a heavy class, you definitely want to put it on the heap, and if needing multiple instances using a vector or map/unordered_map or even an std::deque would be best.

std::unique_ptr does have an array overload, but lacks the out of bounds protection of something like a vector and doesn't support iterators naturally, this is why I didn't bring them up in the list of suggested containers to use.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Firepath
Posts: 77
Joined: March 10th, 2018, 11:53 pm

Re: Wolfenclone

Post by Firepath » August 29th, 2018, 9:24 am

Cool yeh so I am going OK. I have a lot of learning but I knew that. There's a lot of confirmation in what you both have said, of my own thoughts to point me in the right direction.

I guess I now realise that putting thought into where the variables are in memory is a reasonably necessary thing in Cpp. Coming from C# where it's managed for you it is an almost alien concept to HAVE to do it.

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Wolfenclone

Post by albinopapa » August 29th, 2018, 5:43 pm

As my home economics teacher always said, "it's not something you HAVE to do, it's something you GET to do."

In the beginning, I was scared of using heap memory because I was afraid of leaks. I knew I wasn't going to be able to keep track of stuff if the project got too big, this was before smart pointers. While watching chili's videos, he mentioned ownership and responsibility. This sort of gave me some confidence in at least having an idea how to manage memory allocations and deallocations. Then he taught polymorphism, and allocating memory was a must. Once I got the hang of it, I thought, "wow, I can just allocate everything and my stack will be almost empty", so allocated all class objects only leaving the built in types on the stack ( char, int, float, ... ). I hadn't started using references at that point, didn't understand them.

I started using references and liked them so much more for the same reason you do, don't have to use the indirection operator ( operator->). I stopped using them for a while, because they were a hassle to store or more accurately they made it a hassle to instantiate classes if stored. So I resigned myself to using references only for function parameters. This still holds true, mostly, today. If I don't have to move a class or will only instantiate one instance of the class I will store a reference to something. For instance, I will store a reference to a top level class within a nested class. I might have multiple instances of the nested class, but they never get overwritten or replaced since you can't reassign a reference.

Once smart pointers had been out for a while and I had a chance to read up on them ( actually I probably watched more cppcon videos on YouTube than read ) I decided to give them a shot. As you've seen from this thread, I don't have all the answers, Chili and a few others will point me in the correct direction when I'm off. My understanding of smart pointers is:
  • prefer unique_ptr for all allocations to show ownership
  • use shared_ptr when ownership of a resource is shared.
  • pass the underlying raw pointer to functions unless you are transferring ownership.
From this standpoint, I hope you can see why I made such a fuss about storing raw pointers. It's been awhile since I've played with polymorphism especially on a project like yours, so I can't really say how I'd handle the situations you are dealing with.

Somewhere along the way, I started getting hooked on performance. I've always heard that using the stack was faster than using heap memory for a couple of reasons.
  • Heap memory was expensive to allocate.
  • It was less likely the data you want is less likely to be in cpu cache
Through my own experience, it's not the allocations that take the most time, it's the deallocations. It is true that it is less likely to have the data you want in CPU cache if it's stored on the heap, but this isn't always true. If you use the array overload of unique_ptr or a container such as vector, your objects are stored contiguous and cache coherency or data locality isn't much of an issue. Polymorphism still takes a hit in performance as each element is allocated in some random place in memory and not necessarily because of virtual functions. Because I became obsessed with performance, I stopped using polymorphism and preferred stack based allocation. There were other reason I stopped using polymorphism actually. One was because I kept trying to shoehorn it in. I could never seem to find an elegant way of using it and still maintain distinction between their true types when needed. Take for instance two game entities which one has a bounding rectangle and the other a bounding circle. Both are shapes, but have different methods of collision detection and correction. In order to determine the algorithms for collision and correction, you must know the shapes that are colliding. I've tried enums and I've tried runtime type information and neither feel right. I've looked into design patterns such as the "visitor" pattern, but there is too much coupling. Even the "observer" pattern requires polymorphism or some kind of way of determining types.

I believe design patters are the hardest thing for me to understand in programming. I think it's mostly because everyone has their own spin on how to define the pattern, which means I'm left coming up with my own implementation and I hate feeling my way through things.

Wow, this turned into so much more than intended. Good day and good luck.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Firepath
Posts: 77
Joined: March 10th, 2018, 11:53 pm

Re: Wolfenclone

Post by Firepath » September 2nd, 2018, 12:37 am

Did some work, nothing visible - just made the fixture menu structure load from settings file.

Spent way too long trying to fix a retarded bug with menus drawing on top of sub-menus. Difficult to debug 1) graphics and 2) mouse especially together.

I pretty much don't have time to spend on this, I forget what is going on with it and its so hard to get into again each weekend. There's too much shit going on in life, I don't know how I'm supposed to follow my dream and be able to afford a roof above my head, not to mention try and enjoy life before I die. If working on my project was my job, great, I'd be all over it, having continuity from day to day.

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Wolfenclone

Post by albinopapa » September 2nd, 2018, 6:57 am

Wow, yeah, I've heard so many people complain about life getting int he way of their coding. It's understandable if this is just a hobby and all. Just breathe and realize there's no rush on what you are trying to accomplish. Your skills will still be there.

Take care of life and family first, worry about the extra shit when you have time. Once you have the level builder made, what's left? Some drawing routines? Some movement logic? Some level loading bullshit? You got this.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply