Jump to content

TheoLogic

Members
  • Posts

    142
  • Joined

  • Last visited

Posts posted by TheoLogic

  1. It is stupid, it shouldn't add a value in when you're reading from it. They only did this because it has to return a pointer that can be gotten or set:

    a = map[2]
    map[2] = a

    So it's a result of a limitation of the C++ language, because none of this stuff was implemented when they originally designed the thing. Which is why we call C++ an octopus made by nailing extra legs to a dog.

     

    It is not stupid, and clearly defined in the standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf (23.4.4.3 map element access)

     

     

    T& operator[](key_type&& x);

    * Effects: If there is no key equivalent to x in the map, inserts value_type(std::move(x), T()) into

    the map.

    * Requires: mapped_type shall be DefaultConstructible.

    * Returns: A reference to the mapped_type corresponding to x in *this.

    * Complexity: logarithmic.

    • Upvote 1
  2. I think you will find Leadwerks3D to be a lot easier to port. You can probably comment out systems you don't want, or just leave them there and they will take no resources. Everything is pure C++, with no commercial third-party libs, and no **** like Boost built into it. The engine, including all libraries, is about 200,000 lines of code.

     

    Calling Boost ****, shame yourself! Boost developers are mostly active in the C++ ISO committee and create great libraries which eventually may end up in the standard. Best examples are the new C++11 smart pointers and hash containers. I agree with the fact that you don't want to use Boost, it's pretty cumbersome do yet it deployed, but calling it **** crosses the line.

  3. I would say in my experience, enums for that purpose aren't dynamic enough. Ideally all animations would be stored in a database system (sqlite for example) so they can be added/removed without getting into the source. It's just more flexible to do that. Doing that one could make an argument to use an int ID, but to speed up debugging I often find using strings more convenient. It skips a lookup step of trying to figure out what the int value means. If the code hits a breakpoint and I mouse over the animation name variable value and it says "walk" I get more value from that than if it says 25. I'm not a big speed freak though as most basic indie games aren't pushing any boundaries. I value debugging speed and flexibility more than raw run-time speed myself because not to many people are pushing the envelope.

     

    Agreed, your animation example is a good one. I might state as:

    * Static: use enumerations

    * Dynamic: use strings for debug, used hashes in release. You can fairly implement such system that in debug you have access to the actual string value (member of your hash object), but in release it's a hashed version only.

  4. It bothers me to read the title of this thread. A C++ linked list simply doesn't exist. It's a C concept that has been replaced by vectors in C++.

    Vector is not a linked list, an element in a vector does not know the next element... Lists are double linked lists.

     

    I find myself using maps all over the place. I almost always want to look data up easily with a key that I will have handy at the point in which I need to find something in the map. I store animation objects in a map with a string as the animation name so when I press 'W' I can say playAnimation("walk"). I find maps so handy! If I have a list of enemies I give them ID's and use that as the key so when in collision functions I can get the ID of the entity that's colliding to easily find them in the map (if I need this for whatever reason).

    Indeed, maps is probably the most used container after vectors for the reasons you state. I have to agree partially with Josh's comment that you should probably use an "integer type". I suspect he means static const integers, but I would strongly suggest enumerations.

     

    Do they really mean private, or would protected be OK? I find myself only giving functions private access if they are only called the constructor/destructor. Variables I never make private, as I've never found a reason why a derived class shouldn't have access to them.

    Depends, it's rather a design principle. If you don't design your object to be inherited from, just make all members private, else make the members required in the subclass protected. You should never have globals (and if you have them please do add them to a namespace) and public datamembers.

    Really, a book to read for everyone working with C++! It's "just" 101 rules, short book, but very handy.

  5. It doesn't matter, the vector won't scale well when the numbers get big. If you have 10,000 entities, this can result in 40,000 bytes being allocated or copied every single time you create or delete a single entity. The list will always add and remove elements at the same speed. The iteration speed of both will increase linearly with the number of elements.

     

    When designing systems you want predictable performance and scalability. Sacrificing scalability to gain a minute performance increase (in the lightweight scenarios where it isn't even needed) is a bad idea.

     

     

    What? Who said anything about maps?

     

     

    I like being able to access members. It's simple and convenient. It would be silly to call Entity::GetPosition() and allocate a new Vec3 object every time I need to perform some math on an entity, when I can just access the member directly. If you don't like it, don't use them, because there is a getter and setter for anything you need to access.

     

    You should really read this book: http://www.amazon.co...s/dp/0321113586

    Everything you are stating here will gently be countered in 101 rules by Herb Sutter, C++ ISO chairman, and Andrei Alexandrescu. 2 veteran C++ developers! You are burning yourself to the very things they are warning about.

     

    For example:

    7. Know when and how to code for scalability. 14

    10. Minimize global and shared data. 19

    11. Hide information. 20

    41. Make data members private, except in behaviorless aggregates (C-style structs). 72

    76. Use vector by default. Otherwise, choose an appropriate container. 150

    77. Use vector and string instead of arrays. 152

    78. Use vector (and string::c_str) to exchange data with non-C++ APIs. 153

     

    Really, don't take this the wrong way. I broke myself on endless nights, making the same assumptions as you make. That's just what's making C++ so hard!

  6. A vector is a contiguous block of memory. If you remove an element in the middle of it, everything after that element has to be copied to where the element's position was. If you add an element at the end of the vector and it exceeds the size of the memory allocated for that vector, a new block of memory has to be requested, and the entire contents of the container copied to it.

     

    Linked lists have a next and previous pointer for each element. When an element is removed, the program just has to update the memory pointers of the previous and next elements to point to each other, so insertion and removal is fast.

     

    I almost never use vectors.

     

    Oh boy (going off topic).

    Iterating over vectors is faster as over a list. List is node based and vector is a contiguous blocks of memory, which the CPU loves... That's also the reason that C# containers are slower as C++ containers, in C# all (except arrays) are node based. And be honest, what do you use the most? Inserting and removing or iterating?

    * render all items

    * update all items

    Simple examples, this is where you need the performance! Not in that rare case where you need to add or remove for example, this could be done during loading! And even most of the time if you require adding, vector push_back is as fast as list push_back.

     

    And OK, you have a case where you have both: often iterate and often remove in the middle for example. Use move semantics!

     

    Sorry Josh, but you need to work on your C++ skills.

    * Using std::map (red-black binary tree) for entity management? Use objects, or at least std::unordered_map (C++11 hash map) if you really, really, really want to use an ID

    * Using std::list where you want std::vector

    * Public datamembers, just wtf. Encapsulation my friend!

  7. Lists should be used if objects will be randomly removed from the container.

    Why would that be? Just one example how you can handle it:

    for(auto it(myVector.begin()); it != myVector.end(); )
    {
       if(must_remove_this_element)
       {
        myVector.erase(it++);
       }
       else ...
    }
    

     

     

    Or if you don't know the length of the container ahead of time. The last thing you want is lag spike when your data is being copied due to your array or std::vector being re-sized. Assuming your data being housed is large enough to be an issue of course.

    std::vector can reserve capacity, so knowing the maximum number of elements can indeed be a nice thing. However, with move semantics you are able to just move elements on resizing. STL has been modified to support this, so std::vector<std::string> for example will not copy on reallocation, but move. You can write your own move constructor and assignment operator if this is your bottleneck.

  8. First question, do you require a linked-list, or a dynamic array? In my experience, std::vector covers 90% of the container use cases.

    List: http://www.cplusplus.com/reference/stl/list/

    Vector: http://www.cplusplus.com/reference/stl/vector/

     

    Next some remarks on Roland's code:

    for(auto it(myList.begin()); it  != myList.end(); ++it)
    {
      cout <<  *it << endl;
    }
    

    1. Use auto to define iterator types (if you have a C++11 enable compiler). Saves you time, and you can change the container type as you like and don't break your code.

    2. Use '++'-like prefix, especially for iterators. http://thunderguy.com/semicolon/2002/08/13/prefer-prefix-operators-over-postfix/

    • Upvote 1
  9. Powers of two is still the way to go for mipmapping. To generate mipmaps, the size is devided by 2, an some hardware can handle invalid resulting values, but most can not.

    So powers of two doesn't mean square. 512X128 is as valid as 512X512. So what to choose, all really depends your requirements. Big sprites will eventually move to square size depending the platform. iOS for example has a maximum of 1024X1024, Nintendo DSi of 512X512, ...

     

    One remark, for openGL it's faster to load different rectangles from top to bottom. So your second example in the strip, rotate 90°. I am not sure if this is the same for DirectX.

  10. We use Visual Studio 2008 for Windows, Xcode for OSX and iOS, and Eclipse for Android.

     

    I agree with some comments here, VS2008 is not the way to go. For me, the main reason is performance:

    - Secure_SCL is on by default

    - No STL in C++11 form (move semantics for example)

    Both fixed or supported in VS2010.

     

    2 options for the redistributable, static linking or including it in your package.

  11. I personally don't like the syntax, and don't care about the next to nothing savings you get, but also sounds like there are some caveats that come with this.

     

     

    1) The items are not necessarily initialized in the order that they're listed in the initializer list. They're actually initialized in the order in which they're declared in the class.

     

     

    class Foo
    {
     vector<int> vec;
     int count;
    
    public:
     Foo(int val)
     : count(val * 3),
       vec(count)                   // problem because count isn't what you think it is
     {
     }
    };
    

     

    2) They can complicate multiple ctors and produce a lot of redundant code. Say you have a class that has 20 members and 5 different ctors (most of which are initialized the same way for every ctor).

     

    3) Sounded like arrays also can't be in there.

     

     

    No need to get upset (the use of "why the hell" would lead me to believe your passion here) as it doesn't affect you in any way. Lots of people use things in which they weren't intended and the world still goes round :rolleyes: I was just being honest in that I've been using C++ for 10 years and have never used initializer list. I'm not really heavy into C++ right now as I'm using lua more and to change my habits of 10 years most likely isn't going to happen :D

     

    Fully agree, you must actually know C++ to use the initializer lists. Same applies for static's, inheritance, ...

    I also agree that you will have redundant code on big classes (one of the reasons to keep them small and simple), that's why "non-static data member initialization" is introduced in C++11.

     

    I'm not trying to change your habits. Even though I have a passion for C++, I find myself doing much more C# and python lately :). But anyhow, I believe it's a best practice to use the language like it is supposed to. I find myself in the position where I have to maintain legacy C++ code written by COBOL developers, and you won't guess the amount of bugs I found due to uninitialized variables. Before I got here, they've spend 5 months on finding a buffer overflow in old-school C arrays. I refactored the code to use the STL, and it was fixed in 2 hours.

     

    Bottom line, initialize your variables, initializer list or not can be a personal preference. I'll quit talking about this, they'll blame the C++ devs of hijacking threads :).

  12. I guess I'm a bad boy then because I never do that. Honestly I've never had any issues with not doing that. I've never seen any performance issues to worry about, and never had any strange bugs come up because of it. I feel like I'd need a more solid reason to make me change my ways with this. :/

     

    Using the language like it is supposed to? You should always initialize your variables, and you now do this in the constructor body yes?

    If this is the case, why in hell wouldn't you do it in the way the language supports it? I don't see the overhead in initializer list vs constructor body.

  13. How else would you use the initializer list? Not and just putting them in the constructor body? If this is the case, you are loosing performance. You will get a default initialization followed by an assignment! You should always initialize using the initializer list, always, no exceptions. Even if this means nullptr!

    //h
    class Foo
    {
    public:
    Foo();
    
    private:
    int m_whatever;
    MyObject* m_myObject;
    };
    
    
    //cpp
    Foo::Foo()
    :
    m_whatever(0),
    m_myObject(nullptr)
    {
    //Do some stuff so you can actually create m_myObject;
    m_myObject = ...
    }
    

     

    This is the same discussion:

    int blah = 0;
    //vs
    int blah(0);
    

     

    Old compilers will not optimize the first one, and you'll get a default construction and an assignment. If you say premature optimization is the root of all evil, I agree. But this is sometimes faster, never slower so I don't consider this as an optimization...

     

    But here is the good news, C++11 has a feature called "non-static datamember initialization". Once your compiler is updated, you can do:

    class Foo
    {
    private:
    int m_whatever = 0;
    };
    

     

     

    But wandering off-topic. Interesting things though :rolleyes:

  14. Generally when you think about the design of a game and the engine you have to use pointers in some fashion. The engine has to be initialized before you can create models. Generally your entities will be in a class and so doing Model model("mymodel.mdl") in the class declaration isn't possible (not sure about the new C++ but I'm talking original C++ if you will)

     

    C++ without pointers is not really the way to go, but enforcing pointer usage is generally not a best practice... I have nothing against pointers (although I prefer smart pointers over raw pointers), but it is possible to declare a Model (not pointer) and initialize it in your initializer list.

     

    //header
    private:
    Model m_model;
    
    
    //cpp
    MyObject::MyObject()
    :
    m_model("mymodel.mdl")
    { }
    

  15. Model* m = new Model("mymodel.mdl");
    

     

     

    Ctors were made for this. The people who weren't comfortable with C++ complained because the above requires pointers. Pointers are part of the power of C++. Interestingly enough the above works in all 3 languages too :rolleyes:

     

    Agreed, and you don't even need pointers. You can use stack semantics if you want:

    Model model("mymodel.mdl");
    

     

    I even strongly suggest to use smart pointers (and not auto_ptr, but unique_ptr, shared_ptr and weak_ptr).

×
×
  • Create New...