Jump to content
  • Advertisement

GenuineXP

Member
  • Content Count

    510
  • Joined

  • Last visited

Everything posted by GenuineXP

  1. GenuineXP

    To PIMPL or not To PIMPL

    Interesting, I was just wrestling with the same issue in some of my code. I realized since I was maintaining the implementations using boost::shared_ptr objects that the so-called implementation hosts could be used as value types. However, this lead to some confusing syntax (IMHO) and the problem that any data not stored in the implementation but rather in the host object would lead to unnecessary copying (in my case, copying shared signal objects). I too have decided this isn't very desirable. :-) I have also adopted a simple class-level typedef for pointer types as mentioned previously in this thread. class graphics_context : ... { ... public: typedef boost::shared_ptr<graphics_context> ptr; typedef boost::shared_ptr<const graphics_context> const_ptr; ... }; I think this will be much more obvious to users. There's also the problem of deferring instantiation, which would not be possible using value semantics.
  2. Yes, I see now that intelligently handling the loading and unloading of resources is a problem not solved by Boost.Flyweight. It doesn't look like it's very suitable for resource management in a game, and as you stated, building a hash table by hand isn't difficult anyway. That's about all it provides here. Thanks for the input. :-) It's a cool library, and I wanted to explore the applications.
  3. So I've taken a look at the Boost.Flyweight library and it seems quite nifty. I'm curious if it would be good for resource management though. For example, would a setup like the following be reasonable? (I did not try to compile this code; there are probably mistakes.) class resource { public: typedef boost::uint_fast32_t id_type; virtual ~resource(); id_type get_id() const; private: id_type id_; }; struct resource_id_extractor { resource::id_type operator()(const resource &r) const { return r.get_id(); } }; std::size_t hash_value(const resource &r) { boost::hash<typename resource::id_type> hasher; return hasher(r.get_id()); } bool operator==(const resource &lhs, const resource &rhs) { return lhs.get_id() == rhs.get_id(); } typedef boost::flyweight<boost::key_value<typename resource::id_type, resource, resource_id_extractor> > resource_handle; class texture : public resource { }; This would index resources by a unique ID. Coupled with a package system that assigns a unique ID to resources stored on disk, it looks like Boost.Flyweight would provide all the plumping for quick and easy lookup and management of those resources. What do you think? I'm interested in what people think about the library in general as well. Thanks.
  4. Quote:Original post by Telastyn It's the intelligent caching and being able to sufficiently abstract 'how do I load X if it's not there?' variability... Good point. Since they're using a hash table under the hood (at least I assume so), I would hope that caching would also be handled reasonably well by using boost::flyweight objects. Since I would identify resources (statically) with a unique ID, the whole, "How do I load x if it's not there?" part is a matter of the flyweight seeing that the expected ID isn't already in use and constructing a new object (which in turn actually loads the content). I would most likely use strings for IDs and not integers as I did in the above code. As long as resources are always referred to by ID, the flyweights could keep things tidy. ... texture_handle tex0("some-awesome-texture"); // Key not already in use, so construct a texture object, loading the data with that ID. texture_handle tex1("another-amazing-texture"); // Key not already in use; same deal. ... texture_handle tex2("some-awesome-texture"); // Key has been used, so just reference the existing object. ... I figured I would experiment with this in a sort of "package" system I'd like to use. It at least seems to solve part of the problem of resource management. One thing I haven't thought of until now was releasing resources allocated this way. I'm not sure boost::flyweight provides a mechanism for that. Any chance anyone has actually used or attempted this before?
  5. I'm trying to embed Python into a game and have some questions about it. More specifically, I'm trying to use Python to implement parts of a component-based system I'm working on. I'm using Boost Python. All I've done so far is tinkered with the Boost Python wrappers around the Python C API and I've managed to load scripts and evaluate free functions. Eventually, I'd like to be able to: 1.) Load scripts and evaluate generic objects. Given a symbol name "foo", I want to be able to extract its value, whether it be a callable object (like a free function) or a simple variable within the __main__ dictionary. 2.) Expose an API to Python scripts, giving them access to a component object, which is exported from C++. I'm sure these are common ideas. I was wondering if anyone is willing to share their thoughts, experiences, and maybe even code regarding all of this. How have you embedded Python? How do you typically handle the loading and execution of scripts? I don't think I need too much power or low-level functionality (just evaluating objects should be enough). How do you generally go about exposing an API to Python? I think that may be the most difficult part. So far, I'm surprised at how easy it can be to get a Python script running and to extract values from it. Thanks!
  6. GenuineXP

    Polymorphism and templates

    The error message is spot on. You simply cannot create virtual member function templates in C++. One way to get around this (sometimes) is often called a concept, where you supply a class as a template parameter that should provide some interface and implements said concept. template<typename T> class foo { public: void bar() { T::baz(); } }; I'm not sure what you're going for, but maybe that can be helpful. EDIT: Ah yes, as Nanoha said, creating a class template rather than a template member function may also get around the problem and would probably be cleaner than using the technique I described.
  7. Well, the question is summed up in the subject! I'd very much like to use exceptions in a library I'm writing. The problem is, I know how dangerous they can be if the library is compiled into a shared binary (e.g., a DLL or shared object). The good thing is, I think the binary portion of the library will remain fairly small, so static linking is an option. If clients statically link with my code, are exceptions less dangerous? I imagine that they are, since both the client's code and my library code will be linked (or even compiled) by the same tools. If this isn't the case, how can I best support exceptions without making very picky binaries? Thus far, I've been trying to keep any exceptions my code explicitly throws within the library and then resort to error codes. Yuck. If I can avoid this, that'd be great. So... static linking! Better for exceptions? Thanks.
  8. That bit of reasoning sounds good to me. But how do I determine what's a serious enough error to warrant an exception? As an example, for working with raster data in memory, my library provides an image class (actually, image is a proxy that manipulates an underlying plugin object, but that's beside the point). image provides a simple crop member function. Like many of its other member functions, crop returns an integer value indicating the success or failure of the action. One exceptional case is a client call to crop on an image that hasn't been loaded (contains no data). Surely this is not a fatal problem, and effectively renders the call a no-op. So, would this be a good place to forgo exceptions? This situation is very similar to many of the other cases where I've considered using exceptions. Namely, the general problem is calling member functions on objects that don't have an acceptable state (such as swapping the back buffers on a graphics device object before opening a display mode). I suppose I'll employ exceptions, but only where a seemingly unrecoverable problem has occured (i.e., not in the above cases).
  9. Quote:Original post by swiftcoder ...not only will a copy be compiled within the client code, but a separate copy will be compiled inside the library... Nice catch. :) I didn't think about that when I laid that out. I'm still unsure of whether or not I should go ahead and use exceptions? What have others here done in libraries/engines? I'm really not concerned with the performance hit (something I've seen mentioned on these boards in the past), since I'm really not convinced it's significant (unless I'm constantly throwing exceptions for some reason).
  10. Hm, so distributing a static library won't really help in any way then? What would be a good compromise? I could use exceptions, but encourage users to compile my source code themselves and link statically, or I could forgo exceptions entirely and resort to annoying error codes. If I choose to abandon exceptions, would it be worth the trouble then to disable the use of exceptions entirely when I compile the library? Otherwise, the standard library may throw whatever it pleases, potentially causing a crash rather than an opportunity to handle the problem. Another thought: is it at all possible to wrap code within a header so that exception throwing is always compiled into client code? Something like this. foo.hpp ... class foo { public: ... void bar() { if (do_bar() & some_error_mask) { // Do the real work and check for errors. throw std::runtime_error("bar!"); // Okay to throw exceptions here; it's compiled into client binaries. } } ... private: ... int do_bar(); ... }; foo.cpp ... int foo::do_bar() { // Implement the real work here. return send_all_energy_to_flux_capacitor(42, "McFly"); } ... Thanks for the insight!
  11. I haven't started playing with this yet, so I figured I'd ask about it here first. I have a library whose implementation is loaded at runtime. I'd like to be able to report the supported capabilities on a given platform to client code. For example, if the implementation on a target system uses libraries that are unable to load PNG files, but can load JPEG files, clients should be able to use an API to discern this. I'm working in C, btw. Has anyone worked on something like this before? The simplest thought I've had about it is to include some capability enumerators and structs in the library. Then clients can use functions that simply return a list of said enumerators, each representing a capability. In addition, it would be necessary to associate some values with these enumerations (for example, texture support should include details like maximum texture dimensions). I'd like to avoid creating a myriad of functions that each query a single capability. The alternative seems to be to have functions that query a family of capabilities at once, such as graphics capabilities. Anyway, I'm just looking for tips or ideas on how I may want to go about designing/implementing this API; I'm trying to avoid pitfalls. Keeping it simple would be nice, but I'd also like to make something that's robust. Any insight is appreciated. Thanks!
  12. Hm, what exactly are you trying to accomplish; I'm not sure I get it. It sorta sounds like what you're looking for are threads. If I'm understanding correctly, you want to be able to collect user input while continuing to execute the body of the loop (i.e., don't block in a call to std::getline or the like). Is this what you're shooting for? Perhaps you're trying to capture a single character at a time?
  13. So I've actually managed to get away with this in C using GCC in Linux. #define SIZEOF_FOO_INT ( sizeof(int) * 8 - 1 ) #define SIZEOF_FOO_FLAG 1 struct foo { int bar : SIZEOF_FOO_INT; int baz : SIZEOF_FOO_FLAG; }; size_t max_foo_int() { return ( INT_MAX ) >> ( SIZEOF_FOO_FLAG ); } size_t min_foo_int() { /* Bit tricks here. */ } /* Other convenience functions here. */ Please forgive the silly names; I just wanted to throw something together here. I'm wondering, how safe/standard is this? To be more specific, I'm referring to the usage of the sizeof operator to deduce the size of the 'bar' field at compile time. I'm doing this because I need to be able to apply a 1 bit flag to integers of native platform size. For example, on systems where 'int' is 32 bits in size, I want to be able to use 31 of those bits normally (for storing integer values) and 1 of those bits as a flag. On systems where 'int' is 64 bits in size, I want to be able to use 63-bit integers with a similar 1-bit flag. An important assertion is that sizeof(foo) == sizeof(int). This has been working on my development platform, but is it a safe assumption for other platforms as well? In practice, I use macros that apply packing to structs for certain compilers to avoid unnecessary alignment adjustments. Am I off my rocker, or is this a sane approach to getting what I want here? Thanks! EDIT: Added missing multiplication in SIZEOF_FOO_INT macro. [Edited by - GenuineXP on February 13, 2009 11:51:05 AM]
  14. Whoops. Forgot to perform the multiplication in my example code here (it's in my source code though)! Sorry.
  15. GenuineXP

    malloc to new

    I haven't looked at the code because you simply haven't asked anything here. What are you trying to do? Are you worried about the correctness of your code? Will it not compile? These are all questions you need to address when posting, otherwise no one can help you. You probably want to start with what you're trying to accomplish and an overview of the problem. You may find that your approach may not be the best, and people here can give you better alternatives if possible. Good luck.
  16. GenuineXP

    inheritance overkill?

    Quote:Original post by twoaterisn By external objects reading the data, do you mean that i should move the checkcorrectness() outside the atom class? wouldn't this be C-style programming or is it just that i don't get what you're saying? :) Possibly, yes, much like the function foo in my template example accesses the data of bar. In this way, atoms just contain data. Again, depending on exactly what you wish to model, that data could easily be static. If this is the case, it makes more sense for operations to be external (of atoms). As mentioned above, using a table may be the simplest and best suited approach (forget my template ramblings). You could probably implement something like the following. struct atom { // Name, valance, mass, etc. Just data. }; typedef std::vector<atom> atom_con_t; typedef atom_con_t::iterator atom_iter_t; typedef atom_con_t::const_iterator const_atom_iter_t; class molecule { public: molecule(const atom_con_t& table); // References atoms in this table. private: typedef std::vector<const_atom_iter_t> atom_ref_con_t; atom_ref_con_t atoms_; }; void create_atomic_table(atomic_table_con_t& table, std::istream& in); int main() { atomic_table_con_t table; std::ifstream fin("table.dat"); create_atomic_table(table, fin); // Use the table. } Something like this may suffice; it really depends on what you're shooting for. In this example, atoms are just structs that contain atom data (such as valence and atomic mass). A table of atoms (elements) is just a vector of atoms, which could be read from some input stream (like a file). Once this table is created, it can be passed to molecules what store references into the table. I've used iterators here. The typedefs just help keep things clean and easier to remember. What exactly do you plan to model? Knowing this would probably make it easier for others to help you. For example, if you need to model the actual bonds between atoms within a molecule, what I've done here may be too simplistic. EDIT: You could also use a map in this approach, where the key is whatever you would most frequently use to identify a particular atom (probably name or valence). [Edited by - GenuineXP on January 16, 2009 11:28:35 AM]
  17. GenuineXP

    inheritance overkill?

    Hm, what exactly is different about the behavior of the different elements (not the data, like mass, but the behavior)? If there isn't a difference, subclassing probably isn't necessary at all. If there is, is it solely determined by the data? If so, why can't external objects just read the data and determine the proper course of action? One example of this situation I've seen on these forums before is an RPG with character classes. Most people instantly code a base class from which they derive different game classes (bard, warrior, mage, etc.). However, this is often viewed as an abuse of inheritance, since the data (i.e., stats) may be different, but the behavior is essentially the same. Also, I'm assuming that the data for each atom is static and does not change at runtime (this makes sense, unless you're planning on simulating electrons, nuclear reactions, ions and electricity, or some other phenomenon that can alter the state of the atom). In this case, you may want to look into template meta-programming. Using class/struct templates could speed up your code and allow you to do some neat tricks and optimizations. This would probably require a large enumeration though, and could easily lead to code bloat. enum elements { hydrogen, helium }; template<elements E> struct atom { BOOST_STATIC_ASSERT(0 == sizeof(E)); }; template<> struct atom<hydrogen> { enum { some_int_data = 0 }; static const float some_float_data = 0.0f; }; template<> struct atom<helium> { enum { some_int_data = 0 }; static const float some_float_data = 0.0f; }; template<element E> void foo(const atom<E>& bar) { std::cout << bar.some_int_data << std::endl; } Just an idea. Anyway, I hope something here helps. :-) Good luck! [Edited by - GenuineXP on January 16, 2009 10:42:09 AM]
  18. GenuineXP

    Moving objects in tile-based world

    If non-walkable regions are always the entire size of a tile, then performing simple collision checking should work. The key is to use techniques that can quickly rule out whether or not collision checking is needed between certain objects given the current state. I don't have time to elaborate right now, but one technique I've played with before are quad-trees, which can quickly identify if collision checking between objects is necessary. Try a search for those. There are other methods too, and I'm sure someone will post something. :-) Hope this helps. Good luck. EDIT: Actually, the regions don't have to be rectangular or anything. It just simplifies things when you actually determine that a collision check is necessary.
  19. I've been getting interested in programming language design, but I'm finding it difficult to find a lot of resources about the topic. I'd like to develop a toy language that would execute within a virtual machine. If this proves to be too complicated or over my head, perhaps an interpreter would be better than a virtual machine; I really don't know, and that's the point. :-) Does anyone have any recommendations (preferably from experience) on some books that cover this topic? I'd like to find something that could act as a good primer that would equip me to get started actually designing and implementing a toy language. I found Programming Language Pragmatics on Amazon, which seems to have some good reviews. Any links to online articles or resources would be great too; I'm sure I've missed quite a few. I started a similar thread awhile ago and some helpful links were posted there. I'm always looking for more though. I realize that language design and implementation is no simple nor small task, so I'm willing to accept that anything I come up with is likely not going to be able to break the "Hello, world!" barrier. Despite that, I'd still like to learn more. I've already brainstormed some ideas that I think may be interesting to play with, but don't know where to start. I've actually tried to start implementing a runtime using CPython as a reference, but I've hit a lot of brick walls and have found following much of the CPython code pretty difficult without more comments. Thanks for the help!
  20. GenuineXP

    Good Book for Language/Compiler/VM Design?

    Thanks for all the great replies so far. :-) I've heard about the Dragon Book before, but many people seem to think that it's archaic, dry, and difficult to read. I'm sure many books on the topic can be challenging, but I would prefer a more engaging read. What do you think? Is the Dragon Book really that hard to digest? I've only had a chance to briefly scan over some of the Epoch code. I think I'll be able to learn something from it. I'll check out the other links posted here. Thanks again!
  21. I'm wondering if the use of the standard C header stdint.h is okay in C++ code. TR1 seems to offer a cstdint header, but I'm actually interfacing C and C++ code and it seems it would be simpler to forgo differentiating the two headers. I also prefer that these types be defined at global scope. Besides, my TR1 header just includes the stdint.h C header anyway (like many C library headers for C++) and pulls the types into the std::tr1 namespace. Why wasn't this header a part of C++ from the start (i.e., ever since C had the header)? Also, what exactly is the point of Boost's cstdint.hpp header then? Is it more reliable/portable (for example, if you can't be sure TR1 will be available)? When should I prefer Boost's header over the TR1 or C header? Any input is appreciated. Sometimes I wish specifically sized integer types were actually a part of the language.
  22. Ah. I didn't realize that stdint.h was not a part of C89. It makes more sense to me now. Which should I prefer though? I'd like for my code to be reasonably portable, so should I prefer Boost's header or TR1's header? It seems to me that getting your hands on Boost is easier than grabbing a TR1 implementation if you don't already have it, but I'm not sure. Thanks for the information.
  23. GenuineXP

    [C++] Return in destructor?

    Just a thought, but you could also find a sort of middleground with boost::intrusive_ptr. It would require you to implement your own reference counting mechanism while providing similar functionality to boost::shared_ptr. At a minimum, you could use something like this. #ifndef LIB_DETAIL_COUNTABLE_HPP_INCLUDED #define LIB_DETAIL_COUNTABLE_HPP_INCLUDED /** * @file Defines a countable base for reference counting. */ #include <limits> #include <stdexcept> namespace lib { /** * Base for classes that are reference counted. */ class countable { public: typedef unsigned long count_type; countable(): count_(0) {} virtual ~countable() {} void grab() { if (std::numeric_limits<count_type>::max() == count_) { throw std::runtime_error("reference count error: maximum exceeded"); } ++count_; } void drop() { if ((0 == count_) || (0 == --count_)) { delete this; // 'this' shouldn't be used after this call! Consider the object dead. } } count_type count() const { return count_; } private: count_type count_; }; } inline void intrusive_ptr_add_ref(countable* c) { c->grab(); } inline void intrusive_ptr_release(countable* c) { c->drop(); } #endif Something like this could be used, where the grab and drop member functions simply increment or decrement an internal reference count, deleting the object itself when the object is dropped and the count is zero. You can create boost::intrusive_ptr objects that are aware of these member functions, and use them to manage objects. Alternatively, you could implement the reference counting within the intrusive_ptr_* functions. It's up to you. I just wrote up this code now, so don't trust it; I'm just using it to illustrate. Again, just a thought. :-)
  24. GenuineXP

    [C++] Return in destructor?

    I got a laugh out of swallow copy myself. If that isn't meant to be a shallow copy, then I'm interested in what you're using it for. Perhaps some kind of change of ownership mechanism (one reference swallows another)? I haven't actually looked at any of the implementation code, so I really don't know. The two forms of copying semantics in C++ are typically referred to as deep and shallow, which are obviously (and quite intentionally) antonyms. Deep and swallow seem unrelated. :-) Anyway, I have to agree with others in saying that there is no good reason to avoid widely used, understood, and distributed libraries like Boost if they provide the tools and features you're looking for. As far as learning is concerned, why not work on a separate reference counting library project instead? That way, if you intend for others to use this library you're working on, they can be sure that it's built atop tried and tested code. A significant portion of Boost is comprised of solely headers anyway (including boost::shared_ptr), so including it is as easy as... well, just that! Just #include the headers and you're done (no additional linking, etc.). If you do this in your library, all that is required of users (developers) is to have Boost installed. End users don't need anything special. Also, while the usage would seem clean and transparent, I would recommend against attempting to abort destruction within a destructor (reading this very sentence illustrates the problems with this). As soon as you're in the destructor, consider the object in question dead. :-) [Edited by - GenuineXP on January 4, 2009 12:55:35 PM]
  25. GenuineXP

    C as first language

    I'm too lazy to read every reply in this thread, so forgive me if this has already been said. One nice feature of C is that it has many different bindings; it tends to have ways to relatively easily access other libraries and languages. That said, learning C isn't a bad idea in my opinion. For aspects that previous posters have said are unwieldy in C (they are), use those bindings. For example, write logic and the bulk of your code in C, and when you need to build a GUI use Python (GTK+ or Tkinker). You can quite easily make your python and C code talk to each other. One thing to remember is that C and C++ are distinct languages. It's true that C++ is a superset of C, but the idioms used in both languages are very different. Don't be fooled by the infamous "C/C++". [lol] Go ahead and learn C.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!