Sign in to follow this  
darcmagik

Engine Subsystems calling each other

Recommended Posts

Hello everybody I'm back again with another task I'm attempting to solve.  So I'm at a point in my project where I was working on cleaning up some early code that I was using for testing rendering of maps to the screen and I started to realize that I have several of the sub systems for my game engine using a pointer to a graphics object to send their own drawing commands to the graphics system.  I'm looking at this code and I'm wondering if I should let it continue working this way or is their a better way?

 

My original goal for the game engine and the game as a whole was to have each sub system handle one specific task, Graphics, Input, Audio, etc... with the idea that the main class for the game right now simply being called Game having an object for each sub system and the game class would call each systems update method each frame if needed.  The idea being that the Game class would handle calling all drawing commands, it would check for key entry and if so it would update all systems that need to know about it, etc...

 

The problem I'm running into with this so far is that there are several sub systems that need to draw things to the screen and up until now I haven't figured out what the best way would be for them to pass drawing commands without having a pointer to the graphics system object and just calling drawing commands them selves.  So far I have been doing just that passing a pointer around to the systems and letting each system draw but I feel like this may not be the best idea for how to handle this?

 

I'm wondering what everybody's thoughts are? Am I overthinking this and should just let each system have access to drawing or is there a great way to handle this?  I'm not afraid of researching and writing any complex systems if I need to but I am just not sure what the best way to handle this is?

 

Thanks in advance for any and all advice on this topic.

Share this post


Link to post
Share on other sites

Can you be more specific about what systems you're talking about, what dependencies you have between them, and what pointers you're passing around?

 

You might be overthinking this.  If you have a low level graphics system and higher level systems that depend on that, the easiest thing to do is just have a global graphics object/interface that other systems use.  No need to even pass any pointer around because you'd just access the gGraphics (or whatever you call it) object.  If you have to pass a pointer around, that should be a pointer to some context data that actually changes from frame to frame, or render pass to render pass, etc. 

Share this post


Link to post
Share on other sites

So here is what I have I have a class for graphics that creates the DirectX 11 object, and the device context and everything else it needs to get graphics displaying on the screen.  This class also contains a Map that contains all textures in the game they are tied to a name in the map.  This class also contains certain methods for drawing graphics to the screen I have methods like Draw Object which you can pass in the name of the texture and the position you want it at.  I have other methods like that in the class.

 

The other sub systems I'm referring to are like I have a class for the Console window that handles everything related to displaying a console on the screen and accepting commands.

 

I have a system that I'm working on that will be a level editor for the game this level editor right now is only going to be used by the internal team for developing the content for the game but that may change when the game gets closer to release.  This system will be heavily tied in with the Console class.

 

Then I have my map and game world classes the game world class contains all the maps for the game I haven't gotten very far with this class yet as I'm working on just getting a single map displaying on the screen and updating properly with animations and when user input is present.

 

Right now I am passing the graphics pointer from the Game class to Map, and its various classes and what not, and I'm also passing this pointer to the Console and Level Editor classes.

 

I'm a little embarrassed to say that I didn't think of the idea of using an interface to the Graphics system of my game to be honest I have never implemented one before in a class I guess I will need to go do some research on how to properly do this because I do remember reading about using interfaces in game development just never implemented one myself.

Share this post


Link to post
Share on other sites

Start by defining your sub systems. A well defined design would solve almsot all your issues. 

Game engines tend to be more component-oriented. Meaning each "sub system" is a reusable and replaceable component. Each component is an abstract idea.

For example, a "console host" is not abstract, it's a concrete type of a gui.

Therefore you want to define an interface like "IDisplayMessages" (Name might not be the best, but suits the idea for now).

A gui for console would imeplement it with cout, but a gui with openGL rendering would use glfw or glut to implement it.

 

The second thing you want to do is seperating your logic into groups, buisness (Game), graphics (Rendering), input,aduio, database , etc...

A map doesnt need to know how you draw it, it has some system called IDrawingService which does the actual drawing. 

 

*Note:
It may not be the best way to design a real time application, many flaws may arise when trying to speed up the rendering.

Share this post


Link to post
Share on other sites

So here is what I have I have a class for graphics that creates the DirectX 11 object, and the device context and everything else it needs to get graphics displaying on the screen.  This class also contains a Map that contains all textures in the game they are tied to a name in the map.  This class also contains certain methods for drawing graphics to the screen I have methods like Draw Object which you can pass in the name of the texture and the position you want it at.  I have other methods like that in the class.

 

The other sub systems I'm referring to are like I have a class for the Console window that handles everything related to displaying a console on the screen and accepting commands.

 

I have a system that I'm working on that will be a level editor for the game this level editor right now is only going to be used by the internal team for developing the content for the game but that may change when the game gets closer to release.  This system will be heavily tied in with the Console class.

 

Then I have my map and game world classes the game world class contains all the maps for the game I haven't gotten very far with this class yet as I'm working on just getting a single map displaying on the screen and updating properly with animations and when user input is present.

 

Right now I am passing the graphics pointer from the Game class to Map, and its various classes and what not, and I'm also passing this pointer to the Console and Level Editor classes.

 

I'm a little embarrassed to say that I didn't think of the idea of using an interface to the Graphics system of my game to be honest I have never implemented one before in a class I guess I will need to go do some research on how to properly do this because I do remember reading about using interfaces in game development just never implemented one myself.

 

Ok so it sounds like you have a Game class that creates the Graphics object and then passes a pointer to that to anything that needs to render?  This is really not needed because you just create your D3D device and that's what gets used all the time.  So yeah, you just need a global pointer to your Graphics class which you can instantiate once when your app starts (before anything tries to render or create any graphics resources).  If you extern that pointer in your graphics header file then you're set because now anything that includes it can call functions on that class.

 

As far as that graphics class interface, if you make it generic then you can implement it however you want based on what platform you're supporting.  So for now you have just a D3D implementation, but you might want an OpenGL one later.  If your interface doesnt rely on any D3D specific concepts or code, then you should be fine.

Share this post


Link to post
Share on other sites

OK I understand where you are going with that, I'm going back to my project now and see if I can implement things correctly related to what people have suggested.  I will hopefully not be back with more problems related to this but you never know...

Share this post


Link to post
Share on other sites

OK so I am attempting to use an external variable for the graphics system because with the way I'm doing things it seems like the best idea.  So I have an issue with a link error now.  I am defining the extern g_graphicSystem variable inside the Graphics System's Header file at the bottom after the class.  Then in the game class header file I have it defined like I am supposed to from what I am reading in reference material, and in the Game class I call the constructor of the Graphics class to make sure that the new g_graphicSystem variable is defined.

 

The error I'm now getting is if I have the variable declaration inside of the game class I get an unresolved external symbol link error but if I have the declaration line in the game header but outside of the game class I then get a link error related to the g_graphicSystem already being defined.

 

One thing I should point out that may give somebody an aha moment for somebody is that the way my class structure is setup is that the actual game entry point the WinMain is part of a class called Win32_Window this class instantiates a Game variable sets up the loop and then passes control over to the game class so the Win32_Window class basically doesn't get touched again until the window closes.

 

I'm very sorry if what I'm saying sounds like it doesn't make sense but I have been looking at my code for many hours as I attempt to fix all of these crazy issues and try to move the project forward towards completion.

Share this post


Link to post
Share on other sites

OK me again ignore my rants and my dumb questions I figure it out I had to move the actual declarations from the game header file to the game cpp file and the error went away and everything works again so this was a simple dumb error on my part.  But you live and you learn and I have learned quite a bit today so kudos to everybody that gave me their thoughts on this and thanks to everybody on this website because I have learned so much from these forums and the various articles on here as well.

Share this post


Link to post
Share on other sites

OK me again ignore my rants and my dumb questions I figure it out I had to move the actual declarations from the game header file to the game cpp file and the error went away and everything works again so this was a simple dumb error on my part.  But you live and you learn and I have learned quite a bit today so kudos to everybody that gave me their thoughts on this and thanks to everybody on this website because I have learned so much from these forums and the various articles on here as well.

 

Sounds like you solved it.  One thing I would recommend is to separate things out into logical units as much as possible, and try to keep your dependencies so that lower level systems dont have to depend on higher level ones.  So, it sounds to me like you have your graphics code and then your game code, and possibly other code that will need to render stuff.  But, that other code should not depend on the game code, because in theory your game code is the highest level.  What that means is that your g_graphicSystem variable should be declared in the graphics code so that other systems can use it, but not in the game code.

 

Now I dont know exactly how your code is structured, but I'll give some examples going along with what I think you're doing:

 

// lowest level

graphics.h  (extern your g_graphicSystem pointer variable here)

graphics.cpp   (includes graphics.h, define your g_graphicSystem variable here)

 

// mid level

console.h  (includes graphics.h)

console.cpp  (includes console.h, you can now use g_graphicSystem variable here since you included graphics.h through console.h, and dont need to include game.h)

 

// highest level

game.h  (includes console.h)

game.cpp (includes game.h, you can use anything in graphics.h or console.h)

 

Basically you want each system to know only as much as it needs to.  Your g_graphicSystem variable will need to be used in either the graphics, console, or game modules, so you put it at the lowest level... the graphics module.  Then you work your way up from there.  The game module (in this example) is the highest level and you only want other things at that level to include game.h.  So the game module knows about the console module, but the console (or graphics) modules should never need to know about the game module.

 

I hope that's helpful and that I didnt misunderstand your problem.

Share this post


Link to post
Share on other sites

Do what WoopsASword suggested. Split your Console classes into two entities: Console itself and ConsolePresentation. Console has a bunch of typical methods and a pointer to ConsolePresentation. ConsolePresentation is an interface responsible for drawing console contents. This way you'll separate console logic from visualization details and the code related to console rendering will be in one place which will make it easier to maintain in case of changes in Graphics subsystem. Plus as WoopsASword said you'll be able to have different console representations (std::cout, UI or using your renderer).

Share this post


Link to post
Share on other sites

The inconvenience of passing a pointer around is not a sufficient reasoning for tolerating the evilness of globals or singletons!

 

It is common that sub-systems depend on other sub-systems. These dependencies should be directed and acyclic, i.e. a lower level sub-system should never ever call a higher level sub-system. Moreover, a sub-system is not necessarily represented by a single class; from a naming point of view, a "system" is always understood as elements that work together to collectively fulfill a specific task. Graphical rendering, for example, is often implemented as a process passing through several layers and done in several steps: Iterating the scene and collecting renderable entities (perhaps restricted to a specific kind), culling them by visibility, converting them from high level "models" to meshes and textures and shaders, sorting them by some performance criteria, and then sending them to the wrapper behind which the 3rd party graphics API is hidden.

 

I understood the Map class that is mentioned in several posts of the OP as a game level. As such it is a high level data structure (not a sub-system at all, of course). The wrapper for graphical rendering API is a lowest level thing. Hence giving the wrapper a Map instance is already a design flaw.

 

In the end, when a well defined structure of sub-systems is instantiated, pointers need to be passed around for sure. After instantiation, the sub-systems know where their serving sub-systems are, and the need for passing pointers exists just for runtime varying things.

 

Just my 2 cents, of course.

Share this post


Link to post
Share on other sites

The inconvenience of passing a pointer around is not a sufficient reasoning for tolerating the evilness of globals or singletons!

 

It is common that sub-systems depend on other sub-systems. These dependencies should be directed and acyclic, i.e. a lower level sub-system should never ever call a higher level sub-system. Moreover, a sub-system is not necessarily represented by a single class; from a naming point of view, a "system" is always understood as elements that work together to collectively fulfill a specific task. Graphical rendering, for example, is often implemented as a process passing through several layers and done in several steps: Iterating the scene and collecting renderable entities (perhaps restricted to a specific kind), culling them by visibility, converting them from high level "models" to meshes and textures and shaders, sorting them by some performance criteria, and then sending them to the wrapper behind which the 3rd party graphics API is hidden.

 

I understood the Map class that is mentioned in several posts of the OP as a game level. As such it is a high level data structure (not a sub-system at all, of course). The wrapper for graphical rendering API is a lowest level thing. Hence giving the wrapper a Map instance is already a design flaw.

 

In the end, when a well defined structure of sub-systems is instantiated, pointers need to be passed around for sure. After instantiation, the sub-systems know where their serving sub-systems are, and the need for passing pointers exists just for runtime varying things.

 

Just my 2 cents, of course.

 

There's nothing inherently evil about any programming technique or design pattern.  Tools are just tools and they should be used when appropriate.

 

In fact if he already has a Game global object that manages the entire game state, then taking the Graphics object and sticking it in there doesnt remove the global, it just moves it around and creates the need for the Game object to pass that pointer into everything that needs to render.  It dirties up all those interfaces for no good reason, IMO.

Share this post


Link to post
Share on other sites

There's nothing inherently evil about any programming technique or design pattern.  Tools are just tools and they should be used when appropriate.
 
In fact if he already has a Game global object that manages the entire game state, then taking the Graphics object and sticking it in there doesnt remove the global, it just moves it around and creates the need for the Game object to pass that pointer into everything that needs to render.  It dirties up all those interfaces for no good reason, IMO.

[This is a pretty common definition for 'evil' in programming terms -- and under that definition, lots of things are evil (but still used when they are the least-bad option).

As for globals, the epic take-down of that tool was published in 1973... Four decades ago. Every educated programmer should be well versed in the reasons why they're evil.

And as for dirtying up the interface -- by making dependency-passing a part of the interface, you're making the interface self-documenting in that respect; you're making the data-access, data-flow and program-flow patterns visible instead of being magic/hidden/undocumented. In that respect, you're actually cleaning up the interface. An interface that relies on magic/hidden state is dirtier than a self-documenting one IMHO :P

Edited by Hodgman
added link to Wulf et al '73

Share this post


Link to post
Share on other sites

 

There's nothing inherently evil about any programming technique or design pattern.  Tools are just tools and they should be used when appropriate.
 
In fact if he already has a Game global object that manages the entire game state, then taking the Graphics object and sticking it in there doesnt remove the global, it just moves it around and creates the need for the Game object to pass that pointer into everything that needs to render.  It dirties up all those interfaces for no good reason, IMO.

[This is a pretty common definition for 'evil' in programming terms -- and under that definition, lots of things are evil (but still used when they are the least-bad option).

<shrugs>  I'm not really interested in arguing over people's definition of "evil" or other such terms.  That sounds like a religious argument and doesnt really seem productive.  But, I'll say that to me "evil" is something that I consider akin to "something I should never do".  Also, tacking on words like that to complex topics like the use of certain patterns is just a way to turn off your brain and stop thinking about the actual reasons why you should or should not do something.

 

 

As for globals, the epic take-down of that tool was published in 1973... Four decades ago. Every educated programmer should be well versed in the reasons why they're evil.

And if we're talking to a programmer that's not as educated as you are, a better approach would be to point out those reasons rather than to just tell him or her... "dont do it".  That's not really going to help them, especially since by your own definition "evil" doesnt mean "dont do it", it means "usually dont do it, but sometimes it's ok to do it".

 

 

And as for dirtying up the interface -- by making dependency-passing a part of the interface, you're making the interface self-documenting in that respect; you're making the data-access, data-flow and program-flow patterns visible instead of being magic/hidden/undocumented. In that respect, you're actually cleaning up the interface. An interface that relies on magic/hidden state is dirtier than a self-documenting one IMHO  :P

Any engine will have a certain set of assumptions that come with it, and it will have a certain level of knowledge that the user will need.  What level is acceptable is highly dependent on the specific cases.  You cant categorically say that any level of knowledge outside of function parameters is unacceptable.

 

As far as this specific case, like I said it doesnt make the Graphics pointer not global, it just hides it inside another global (the Game object).

Edited by 0r0d

Share this post


Link to post
Share on other sites

<shrugs>  I'm not really interested in arguing over people's definition of "evil" or other such terms.  That sounds like a religious argument and doesnt really seem productive.  But, I'll say that to me "evil" is something that I consider akin to "something I should never do".

 

Language changes. Different subcultures (and the programming world very much is a subculture) often warp the definitions of words. It makes the prescriptivists cry, I know, but if everyone else is using a word "wrong," one often finds that one needs to adapt.
 

Also, tacking on words like that to complex topics like the use of certain patterns is just a way to turn off your brain and stop thinking about the actual reasons why you should or should not do something.


Which isn't a good thing - in theory. The trouble is that we as programmers often work on systems that are sufficiently complex that it's advantageous to find ways to reduce cognitive loading on ourselves. So - practically, not thinking about why you shouldn't do something can be a good thing if it frees up enough mental space to actually accomplish the task at hand. Where this becomes dangerous is where one adopts a strategy to reduce cognitive loading and then refuses to relinquish it.
 

Any engine will have a certain set of assumptions that come with it, and it will have a certain level of knowledge that the user will need.  What level is acceptable is highly dependent on the specific cases.  You cant categorically say that any level of knowledge outside of function parameters is unacceptable.


No. He says it's "evil" - given the common programmer meaning of that word, which Hodgman gave you, which you have apparently rejected. His use of the term may not match yours, but interpreting words solely according to your own idea of what they should mean, without consideration for how others use them, is a recipe for misunderstanding.
 

As far as this specific case, like I said it doesnt make the Graphics pointer not global, it just hides it inside another global (the Game object).


Why does the Game object need to be a global? And anyway, Hodgman is talking about interface cleanliness - about non-explicit state dependencies, not globals per se. Non-explicit state dependencies come in many forms, not just globals.

Of course, globals have other problems in multithreading environments , and singletons in C++'11 in particular have a multithreading-related gotcha (depending on how they're initialized) that isn't immediately obvious - but that wasn't the focus of his argument. Edited by Oberon_Command

Share this post


Link to post
Share on other sites

 

As far as this specific case, like I said it doesnt make the Graphics pointer not global, it just hides it inside another global (the Game object).


Why does the Game object need to be a global? And anyway, Hodgman is talking about interface cleanliness - about non-explicit state dependencies, not globals per se. Non-explicit state dependencies come in many forms, not just globals.

Of course, globals have other problems in multithreading environments , and singletons in C++'11 in particular have a multithreading-related gotcha (depending on how they're initialized) that isn't immediately obvious - but that wasn't the focus of his argument.

 

 

I'm going off of the description of the code/engine described by the op.  Unless I misunderstood, he said that he has a top level global Game object, which is not an unreasonable thing for him to have.

 

Yes, globals have many issues and multithreading is a major one.  But the OP appears to have a simple engine with a simple set of problems that he was asking about.  I tried to limit my responses to that context.  Of course I could start talking about all the things he should or shouldnt do because of MT or multi-platform considerations and all that, but it would only confuse him and derail the thread.  My goal was to help the OP in the easiest and clearest way possible that would allow him to move forward with his specific question.

 

Edit: Forgot to answer the "interface cleanliness" issue.  Yes, minimizing implicit state is a good thing.  However, I dont think it's in any way confusing for an engine to say that it has some set of systems that exist that are globally available like graphics, audio, file IO, logging, etc.  These would be understood to be created and initialized at game startup and in the correct order, and thereafter are always available.  The nice thing about this is that anything that needs them can now access them, rather than having to always pass them down as input parameters from higher levels to lower levels.   IMO this: Game::Update(float dt) is much cleaner than this: GameObject::Update(AudioSys* pAudio, IoSys* pIO, LoggingSys* pLogging, float dt).

Edited by 0r0d

Share this post


Link to post
Share on other sites

The nice thing about this is that anything that needs them can now access them, rather than having to always pass them down as input parameters from higher levels to lower levels.


It's certainly convenient - but convenience isn't always "nice" as Hodgman pointed out. "Convenience" leads to what we call "abuse." If globals and singletons are widely used in a codebase, then it becomes easier to justify adding more of them. The result will be a mess of global state at various amounts of coupling.

It is sometimes useful to sacrifice some clarity on the fragment level to achieve clarity on the system level.

IMO this: Game::Update(float dt) is much cleaner than this: GameObject::Update(AudioSys* pAudio, IoSys* pIO, LoggingSys* pLogging, float dt).


But this raises other questions. Why does a GameObject need to know about the IO system? Why does it need to know about the audio system and the IO system in the same place? The second way makes it clearer when I could benefit from refactoring my update out into separate passes that deal with one aspect of an object's update - see the "Single Responsibility Principle", which applies to methods as much as it does to classes. I can attest from experience that this has proven very helpful in keeping the overall codebase (as opposed to individual fragments) more straightforward. Edited by Oberon_Command

Share this post


Link to post
Share on other sites

Wait, why are pointers so evil(according to isocpp) again? I have never been introduced to this idea before. I myself love pointers...

Edited by ExErvus

Share this post


Link to post
Share on other sites

I had to move the actual declarations from the game header file to the game cpp file and the error went away

 

ideally, only stuff that has to be externally public should go in the header file.

 

as stated by Hodgman, while passing pointers is a pain, it does make the code more self-documenting, and therefore easier to maintain - assuming the maintainer stops to read what it's doing.

 

one way to reduce the pain is to create a struct to hold the commonly passed pointers, and simply pass the struct by reference. this at least cleans up the API calls a bit.

Share this post


Link to post
Share on other sites

Wait, why are pointers so evil(according to isocpp) again? I have never been introduced to this idea before. I myself love pointers...

Probably because they want you to use smart-pointers and references.
Raw-pointers are an extremely common source of memory management bugs.

Share this post


Link to post
Share on other sites

 

Wait, why are pointers so evil(according to isocpp) again? I have never been introduced to this idea before. I myself love pointers...

Probably because they want you to use smart-pointers and references.
Raw-pointers are an extremely common source of memory management bugs.

 

And even with smart pointers, raw pointers are still actively used. My definition of "evil" in programming means, "by default, it's not the right choice, so if you think you need it, think twice over before continuing."

The key is knowing when to use what tool, but to have your defaults ready. By default, unique_ptr and shared_ptr and weak_ptr make more sense, but raw pointers are still used for non-owning access where the lifetime of the object is garunteed to outlast the lifetime of the pointer. Usually these are and usually cycle-breaking relationships, like a child pointing at its parent (the parent is implicitly guaranteed by the code, not the documentation, to never 

 

By default, one should avoid GOTOs, but in hyper-rare scenarios, a GOTO can be useful.

 

By default, one should avoid (non-const) globals (because you want to enforce your access guarantees in your code as much as possible, not merely your documentation), but there are some cases where (A) the global truly isn't harmful, and even rarer cases where (B) the harm is actually the lesser of two evils. But by default, you want to be extra vigilant and see if there are better solutions first.

 

One example of a non-const global that isn't harmful is a logging system. This isn't harmful because logging systems are usually the inverse of const: They are write-only, rather than read-only, so it still makes it impossible for the logging system to invisibly change the state of your sub-systems. There are flexibility reasons why you may want more than one logging system, though, or a separate logging system for different sub-systems (or more likely, separate threads in a multithreaded project); but those are steps up in complexity, and a write-only logging system in a single-threaded project is one example of a safe global.

A rendering system might also meet this definition of write-only, but because rendering systems are alot more complex, multi-layered, low-level, and often call into the OS and videodriver, and have multiple behind-the-scenes implementations depending on the platform, I wouldn't assume it is safe until I can validate that assumption on a case-by-case basis and then enforce that in the code.

 

I don't use defaults to turn off my brain, I use it as an early warning system to alert my mind to be extra vigilant if I choose anything other than the default. i.e. I use code smells.

Share this post


Link to post
Share on other sites

 

Wait, why are pointers so evil(according to isocpp) again? I have never been introduced to this idea before. I myself love pointers...

Probably because they want you to use smart-pointers and references.
Raw-pointers are an extremely common source of memory management bugs.

 

 

Right, but that is on the developer as a problem he has to keep in check and use correctly, just like any other aspect of programming. That's like saying someone might try to tighten a screw with a wrench, so just incase, we recommend using a power drill instead.

Edited by ExErvus

Share this post


Link to post
Share on other sites

Wait, why are pointers so evil(according to isocpp) again? I have never been introduced to this idea before. I myself love pointers...

Probably because they want you to use smart-pointers and references.
Raw-pointers are an extremely common source of memory management bugs.

 
Right, but that is on the developer as a problem he has to keep in check and use correctly, just like any other aspect of programming. That's like saying someone might try to tighten a screw with a wrench, so just incase, we recommend using a power drill instead.


Even if you know what you're doing, and you know all that needs to be known to avoid memory bugs in C++, it's still extra work for you to get it right. It's more that you have to think about. Remember what I said earlier in the thread about cognitive loading? Maybe in some cases thinking about exactly when your memory is going to be released is useful, but in a lot of cases, it's entirely tangential to the goal of actually processing some data. Using a smart pointer is a way to use other programmer's thoughts to reduce how much you as the programmer have to think, and because the smart pointer code is only written once, there isn't a proliferation of custom solutions that your inevitable successors (whom you do care about, right? Might even be you, three years from now!) have to decode when they touch your code.

Using smart pointers/references can also help your successors understand your code by making some aspects of your ownership semantics verifiable by the compiler, and where it isn't verifiable, at least explicit to the humans reading it how a pointer is supposed to be used.

Would you use a hand screwdriver to tighten a screw if you happened to have a power drill on hand, and didn't have some reason not to use the power drill? Edited by Oberon_Command

Share this post


Link to post
Share on other sites

Wait, why are pointers so evil(according to isocpp) again? I have never been introduced to this idea before. I myself love pointers...

Probably because they want you to use smart-pointers and references.
Raw-pointers are an extremely common source of memory management bugs.
 
And even with smart pointers, raw pointers are still actively used. My definition of "evil" in programming means, "by default, it's not the right choice, so if you think you need it, think twice over before continuing."

That's also pretty much how the document being referenced by ExErvus defines it.
They even admit that "evil" is deliberate exaggeration used to create emphasis through comedy and offer “frequently undesirable” as a euphemism  :wink:

Right, but that is on the developer as a problem he has to keep in check and use correctly, just like any other aspect of programming. That's like saying someone might try to tighten a screw with a wrench, so just incase, we recommend using a power drill instead.

Did you even read their explanation? You're saying what they're saying :P

"One size does not fit all. Stop. Right now, take out a fine-point marker and write on the inside of your glasses: Software Development Is Decision Making. “Think” is not a four-letter word. There are very few “never…” and “always…” rules in software — rules that you can apply without thinking — rules that always work in all situations in all markets — one-size-fits-all rules.
In plain English, you will have to make decisions, and the quality of your decisions will affect the business value of your software. Software development is not mostly about slavishly following rules; it is a matter of thinking and making tradeoffs and choosing."

 
So, no, it's not like saying use this extreme tool because some people might use the wrong tool. It's more like saying, "hey, exposed wires are dangerous, so most of the time you should remember to keep them insulated, and use pre-insulated wiring as your default choice". Or "it's safer to wear gloves when operating the drill". :lol:
 
At all the console game development companies that I've worked for, smart pointers have been quite rare, as there's often been a strong C programming culture (i.e. the C++ as C-with-classes style) and the C++ standard library and even language features such as templates have been shunned in the past due to terrible performance on console hardware from two generations ago. That's over a decade of professional C++ with raw pointers, and near on two decades of hobbyist use... but still, this week I was working as a C++ contractor on a game engine, and I committed a memory-leak bug to the project, and found a buffer-underrun-memory-corruption bug (in certain cases, array[-1] = x would occur) in code that I'd previously written for them and which has actually already shipped on two console titles... That's two potentially-dangerous-yet-often-invisible bugs in one week from one of their senior engineers... Even a static analysis of God-figure John Carmack's C/C++ code has found these kind of bugs! Think how many of these invisible yet potentially deadly bugs could constantly be slipping in from the less experienced engineers :(
If we'd been following the best practices and common advice such as in those links, these bugs would've been much less likely to get written, which is why it's a good thing to teach them as the default choice to use before you weigh up your options.
Thankfully, this particular company has amazing continuous-integration quality control now, which picked up on both of my bugs instantly. If you're going to play with these dangerous tools, you do need to set up a workflow to mitigate their risks, such as automatic testing of every commit made to your repo, and using a memory allocator during development that has full tracking/logging abilities, use-after-free detection, and out-of-bounds access detection... which isn't something simple to set up.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this