Thread: Long Lines of Code, and Passing a reference to an array Question

  1. #1
    C++ Enthusiast M.Richard Tober's Avatar
    Join Date
    May 2011
    Location
    Georgia
    Posts
    56

    Long Lines of Code, and Passing a reference to an array Question

    This may not be the best way to write this:
    Code:
            double TempRandX = EnemyLowerBounds.x + (static_cast<double>(rand() % ((EnemyLowerBounds.x - EnemyUpperBounds.x) * 10)) * 0.1);
    This is the 4th day on this project and the code is way clearer than my first prototype, believe me. Comments welcome!

    I have this also:
    Code:
    void Enemy::SetPersonality(const int (&RefPersonality)[20])
    {
        for (int i = 0; i < 20; ++i)
        {
            Personality[i] = RefPersonality[i];
        }
    }
    I know the above in my previous draft was this:
    Code:
    void Actor::SetPersonality(int *NewPersonality) {
        for (size_t i = 0; i < 20; ++i) {
            Personality[i] = NewPersonality[i];
        }
    }
    The Reference solution seems more C++ ish, but it's definitely more convoluted.
    Are there compelling subtleties to passing an array by reference, versus pointer?

    Edit: Grr, I have to do even more casts in the top line to get it to compile. Be right back.

    Edit 2:
    Code:
            // Random Position
            double TempRandX = EnemyLowerBounds.x + (static_cast<double>(rand() % (static_cast<int>((EnemyLowerBounds.x - EnemyUpperBounds.x)) * 10)) * 0.1);
            double TempRandY = EnemyLowerBounds.y + (static_cast<double>(rand() % (static_cast<int>((EnemyLowerBounds.y - EnemyUpperBounds.y)) * 10)) * 0.1);
            double TempRandZ = EnemyLowerBounds.y + (static_cast<double>(rand() % (static_cast<int>((EnemyLowerBounds.y - EnemyUpperBounds.y)) * 10)) * 0.1);
    
            TempRandZ = -28.0;  // Currently all actors are locked to -28.0z
    It compiles now... heck it may even work - but it's a terrible mess.
    Last edited by M.Richard Tober; 10-25-2011 at 06:51 AM. Reason: Pressed Compile =/

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > double TempRandZ = EnemyLowerBounds.y +
    I'm guessing you meant EnemyLowerBounds.z ?

    Create some small utility functions which you can then declare as inline if you need to later on.
    The clue is when you start copy/pasting and doing some kind of substitution (or not as the case may be).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    C++ Enthusiast M.Richard Tober's Avatar
    Join Date
    May 2011
    Location
    Georgia
    Posts
    56

    Thank you Salem!

    Code:
            double TempRandZ = EnemyLowerBounds.z + (static_cast<double>(rand() % (static_cast<int>((EnemyLowerBounds.z - EnemyUpperBounds.z)) * 10)) * 0.1);
    Yes, so sorry about that - the Z coords are actually locked until everything is cool with just 2 dimensions.

    Now, about utility functions:

    I'm really into modularity and separating Classes into a Class.cpp, and a Class.h, and putting enumerators into the classes they're used in, etc - So, lemme think how to explain this. I do not want to simply post walls of my code - that's annoying.

    Code:
    #include <iostream>
    #include <vector>
    #include <cstdlib>
    #include <ctime>
    #include <cassert>
    
    #include <SFML/Window.hpp>
    #include "main.h"
    #include "entity.h"
    #include "actor.h"
    #include "player.h"
    #include "enemy.h"
    
    using namespace std;
    
    using sf::Window;
    using sf::Clock;
    
    void InitWindow(Window &Game);
    void InitEnemies(vector<Enemy*> &RefEnemies,
                     const unsigned int &RefNumOfEnemies,
                     Enemy::vec3d &EnemyUpperBounds,
                     Enemy::vec3d &EnemyLowerBounds);
    void GetInput(Window &Game);
    void Update();
    void Render(Window &Game); //void Render(sf::Window &Scene, vector<Actor> &Enemies, Actor &Player, Actor &Camera);
    void ShutDown(Window &Game);
    
    int main()
    {
        ///////////////
        // Constants //
        ///////////////
    Okay, so, the idea I'm portaying is that #1 - I don't know what functions to keep in main, or (re-factor?) into classes, and then, further more - my functions I do have end up taking references to like.... everything.

    Here is that exemplified in my last draft, which is what my new 'cleaner' code is heading towards:
    Code:
    #include "actor.h"
    #include "main.h"
    
    using namespace std;
    
    void Init(sf::Window &App);
    void Setup(const int &numEnemies, std::vector<Actor> &Enemies);
    void Input(sf::Window &App, Actor &Player);
    void Update(std::vector<Actor> &Actors, Actor &Player);
    void Render(sf::Window &Scene, vector<Actor> &Enemies, Actor &Player, Actor &Camera);
    You can see above, how eventually it seems every major function needs (handles?) references to every major object or vector of objects in the game!

    I just don't know if this is how professionals do this, and I'm self-taught. I'm trying to follow the examples and mindsets of people like lazerlight and the other mods because there expertise is apparent.

    So... are this things that just become instinctual after a long time coding? When I'm done with this current re-factoring/cleaning/organizing, I'll send ya a copy of my source is ya like. It's a really cool 3-D scene where 100 little cubes change behaviors intermittently, colors (depending on behavior), and you control a little cube that they respond to.

    I digress, I can only imagine the demands on the time of the mods of these forums. As always, any insight is most welcome!
    Last edited by M.Richard Tober; 10-25-2011 at 07:18 AM. Reason: Brain melted, yet I type on.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Well, Init, Setup, Input, etc seem to belong to the main logic, which should then appropriately be placed into main (or you could try chopping them into blocks and placing them in separate source files).
    So Window, Actor, etc would go into their own files. They're pretty separate from each other, so that should be fine.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    C++ Enthusiast M.Richard Tober's Avatar
    Join Date
    May 2011
    Location
    Georgia
    Posts
    56
    Holy moly, when I read your affirmation Elysia, I actually sighed in relief. *laugh* I think I'm my own worst critic, but that's probably for the best. Thank you to you and Salem, I'd be up the iostream without a paddle if it wasn't for this website.
    Eventually, I decided that thinking was not getting me very far and it was time to try building.
    — Rob Pike, "The Text Editor sam"

  6. #6
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by M.Richard Tober View Post
    Are there compelling subtleties to passing an array by reference, versus pointer?
    Passing an array by reference will make the type system check that the passed array has exactly 20 elements. Also, sizeof will return the size of the array, not of a pointer. However, it isn't that common to use array references. Often a fixed size array can be abstracted as an object, and so would be wrapped in one. Dynamic arrays cannot be passed as array references. There are cases when a part of an array may be treated as an array. Reference syntax would not allow this without casting.

    As an aside, it's bad practice to use magic numbers, like 20. Instead use a constant.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  7. #7
    C++ Enthusiast M.Richard Tober's Avatar
    Join Date
    May 2011
    Location
    Georgia
    Posts
    56

    Thank you!

    Thanks KingMir! So it sounds like generally is a better idea to use references than pointers to pass arrays...
    ... but now I have a terrible new issue:

    Nested iterators...? I don't even know how to describe my problem.

    Declaration:
    Code:
    void Update(vector<Enemy*> &Enemies,
                vector<Player*> &Players);
    Called like so:
    Code:
        double GameLoopTimeLimit = 0.0166 * GameLoopTimeAdjust;
    
        while (Game.IsOpened())
        {
            if (UpdateClock.GetElapsedTime() > GameLoopTimeLimit) {
    
                for (vector<Actor*>::iterator it = Players.begin(); it != Players.end(); ++it)
                {
                    GetInput(Game, it);
    
                    Update(Enemies, Players);
                }
                UpdateClock.Reset();
            }
            Render(Game, Camera, Players, Enemies);
        }
        ShutDown(Game);
        return EXIT_SUCCESS;
    }
    Definition:
    Code:
    void Update(vector<Enemy*> &Enemies,
                vector<Player*> &Players)
    {
        for (vector<Enemy*>::iterator itE = Enemies.begin(); itE != Enemies.end(); ++itE) {
            for (vector<Player*>::iterator itP = Players.begin(); itP != Players.end(); ++itP) {
                (*itE)->Update(*itP);
            }
        }
    }
    Errors:
    Code:
    /storage/Projects/Recent/Mon Oct 24/main.cpp||In function ‘int main()’:|
    /storage/Projects/Recent/Mon Oct 24/main.cpp|121|error: invalid initialization of reference of type ‘std::vector<Enemy*>&’ from expression of type ‘std::vector<Actor*>’|
    /storage/Projects/Recent/Mon Oct 24/main.cpp|59|error: in passing argument 1 of ‘void Update(std::vector<Enemy*>&, std::vector<Player*>&)’|
    /storage/Projects/Recent/Mon Oct 24/main.cpp||In function ‘void Update(std::vector<Enemy*>&, std::vector<Player*>&)’:|
    /storage/Projects/Recent/Mon Oct 24/main.cpp|139|error: no matching function for call to ‘Enemy::Update(Player*&)’|
    /storage/Projects/Recent/Mon Oct 24/enemy.h|24|note: candidate is: void Enemy::Update(Actor&)|
    ||=== Build finished: 4 errors, 0 warnings ===|
    I created this program from scratch, so... it's gonna be strange. What's going on here, is a Base Class <Actor> has been inherited by two child classes, <Enemy> and <Player> - there's 100 enemies and 1 player, but to leave open the chance for more players, I've handled both as vector<Actor*> for most of my program.

    What this Update is trying to do is loop through all 100 enemies while checking a variable number of player objects each game loop. (*itE)->Update(*itP); is where it then calls the Update Function of the Current Enemy Object with the Current Player being fed into it (to check for distance from that player, between the two)

    I've had it working, then failing, and this is the 5th incarnation of this function. I prolly need to call it a session and come back later.

    As always, any insight = Awesome.

    And, I get that I'm already IN a loop of players, and it's a little bit of a mess. I'd like to call Update with a Reference to a vector of <Enemy*> pointers, and simply feed it the current player as a 2nd argument. My logic has derailed a bit - I'll hit it up in a bit after some tea and a shower.

    I'll get back with some working code within the day.
    Eventually, I decided that thinking was not getting me very far and it was time to try building.
    — Rob Pike, "The Text Editor sam"

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It's difficult to see what lines the errors are referring to. Mind pointing them out?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    C++ Enthusiast M.Richard Tober's Avatar
    Join Date
    May 2011
    Location
    Georgia
    Posts
    56
    Sorry! Sure, give me a minute.

    Code:
       while (Game.IsOpened())
        {
            if (UpdateClock.GetElapsedTime() > GameLoopTimeLimit) {
    
                for (vector<Actor*>::iterator it = Players.begin(); it != Players.end(); ++it)
                {
                    GetInput(Game, it);
    
                    Update(Enemies, Players);       <--- Line 121
                }
                UpdateClock.Reset();
            }
            Render(Game, Camera, Players, Enemies);
        }
        ShutDown(Game);
        return EXIT_SUCCESS;
    }
    /storage/Projects/Recent/Mon Oct 24/main.cpp|121|error: invalid initialization of reference of type ‘std::vector<Enemy*>&’ from expression of type ‘std::vector<Actor*>’|

    Code:
    void Update(vector<Enemy*> &Enemies,
                vector<Player*> &Players);
    Line 59: /storage/Projects/Recent/Mon Oct 24/main.cpp|59|error: in passing argument 1 of ‘void Update(std::vector<Enemy*>&, std::vector<Player*>&)’|

    Code:
    //////////////////////////
    // Function Definitions //
    //////////////////////////
    void Update(vector<Enemy*> &Enemies, Player &Player)
    {
        for (vector<Enemy*>::iterator itE = Enemies.begin(); itE != Enemies.end(); ++itE)
        {
    Line 138:    for (vector<Player*>::iterator itP = Players.begin(); itP != Players.end(); ++itP)  <-- 138
            {
                (*itE)->Update(*itP);
            }
        }
    }

    Line 138:
    /storage/Projects/Recent/Mon Oct 24/main.cpp|138|error: ‘Player’ cannot appear in a constant-expression|
    /storage/Projects/Recent/Mon Oct 24/main.cpp|138|error: template argument 1 is invalid|
    /storage/Projects/Recent/Mon Oct 24/main.cpp|138|error: template argument 2 is invalid|
    /storage/Projects/Recent/Mon Oct 24/main.cpp|138|error: expected initializer before ‘itP’|
    /storage/Projects/Recent/Mon Oct 24/main.cpp|138|error: ‘itP’ was not declared in this scope|
    /storage/Projects/Recent/Mon Oct 24/main.cpp|138|error: ‘Players’ was not declared in this scope|


    Elysia,
    I know it's wack. I'm gonna chew on it and get the logic back in order. I really need to learn a great way to iterate over the vector of Enemy pointers, activating each Enemy's Update function, and feeding those function a Player to check against from a separate vector of pointers to Players.

    I know there's better technology and technique out there for this, but I don't know it, and feel I really need to go through this to get there. =/
    Eventually, I decided that thinking was not getting me very far and it was time to try building.
    — Rob Pike, "The Text Editor sam"

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    So for line 121, are you sure that you aren't shadowing Enemies somewhere in the function? The compiler complains that it's of type std::vector<Actor*>, and you cannot pass a vector of type T1 to a function expecting a vector of T2.
    As for line 138, you've misspelled "Players." The argument in your function is called "Player."
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    C++ Enthusiast M.Richard Tober's Avatar
    Join Date
    May 2011
    Location
    Georgia
    Posts
    56
    I'm lost in a hellish world of pointers and references, which I now call "Crouching Tigers and Hidden Dragons" =(

    I'll get back with updates soon.
    Eventually, I decided that thinking was not getting me very far and it was time to try building.
    — Rob Pike, "The Text Editor sam"

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You may want to look into using smart pointers, too.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    C++ Enthusiast M.Richard Tober's Avatar
    Join Date
    May 2011
    Location
    Georgia
    Posts
    56

    Thank you Elysia :)

    I'm brushing up on virtual functions right now. I thought I knew how to implement the polymorphism I needed to let the Parent class <Actor> to have a virtual void Update(); that would allow a call like *(Actor)->Update(...) to automatically use Class Enemy's Update function.

    I dropped the ball though, so it's back to the tutorials for a refresher.

    Code:
    /storage/Projects/Recent/Mon Oct 24/main.cpp|137|error: ‘class Actor’ has no member named ‘Update’|
    WE SHALL SEE ABOUT THAT COMPILER!

    And as for Smart pointers - I already do too much damage with dumb ones. >=)
    Eventually, I decided that thinking was not getting me very far and it was time to try building.
    — Rob Pike, "The Text Editor sam"

  14. #14
    C++ Enthusiast M.Richard Tober's Avatar
    Join Date
    May 2011
    Location
    Georgia
    Posts
    56

    Polymorphism, or: How I Learned to Stop Worrying and Love the Bomb

    In my base class <Actor>, I defined

    Code:
    virtual void Update(Actor &Player);
    ...This caused a vtable meltdown - but without me knowing what was going on, I over-reacted and hacked up a bunch of working code! Argh. So... here's the solution! Add braces!

    Code:
    virtual void Update(Actor &Player) {};

    Original Error Messages:
    Code:
    obj/Debug/enemy.o||In function `~Actor':|
    /storage/Projects/Recent/Mon Oct 24/actor.h|24|undefined reference to `vtable for Actor'|
    obj/Debug/enemy.o:(.rodata._ZTI5Enemy[typeinfo for Enemy]+0x10)||undefined reference to `typeinfo for Actor'|
    obj/Debug/main.o||In function `Actor':|
    /storage/Projects/Recent/Mon Oct 24/actor.h|23|undefined reference to `vtable for Actor'|
    obj/Debug/player.o:(.rodata._ZTI6Player[typeinfo for Player]+0x10)||undefined reference to `typeinfo for Actor'|
    ||=== Build finished: 4 errors, 0 warnings ===|
    Why?

    This error is caused by declaring but not implementing one or more virtual function.

    How to Fixed It?

    Provide implementation to all virtual functions. If you declare the function, you MUST provide the implementation, even if it is an empty implementation. Otherwise, you will see the above error message.
    Thank you Elysia, Mir, and Salem for some excellent back-and-forth discussion, encouragement, and patience. You all stand as shining examples of the effort moderators and members put into these forums.
    Eventually, I decided that thinking was not getting me very far and it was time to try building.
    — Rob Pike, "The Text Editor sam"

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by M.Richard Tober
    This caused a vtable meltdown - but without me knowing what was going on, I over-reacted and hacked up a bunch of working code! Argh. So... here's the solution! Add braces!
    It is just a linker error: the "undefined reference" is a hint that you may have forgotten to define something.

    That said, in this case it may be better to make Update a pure virtual instead:
    Code:
    virtual void Update(Actor &Player) = 0;
    in which case you do not need to provide a definition for Actor::Update, and derived classes that are concrete are required to override this virtual member function.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Passing an array as reference to a function?
    By Kylecito in forum C++ Programming
    Replies: 10
    Last Post: 03-11-2006, 02:25 AM
  2. Passing array by reference
    By TBc in forum C++ Programming
    Replies: 4
    Last Post: 12-11-2005, 08:48 AM
  3. Passing a 2d array by Reference
    By loko in forum C Programming
    Replies: 8
    Last Post: 07-23-2005, 06:19 AM
  4. passing a reference to an array?
    By Captain Penguin in forum C++ Programming
    Replies: 5
    Last Post: 10-03-2002, 03:10 PM
  5. Passing Array by Reference...
    By Cheeze-It in forum C++ Programming
    Replies: 5
    Last Post: 02-22-2002, 01:29 PM

Tags for this Thread