Jump to content

  • Log In with Google      Sign In   
  • Create Account


Trienco

Member Since 22 Aug 2001
Offline Last Active Apr 15 2014 10:44 PM
-----

#4927117 Forward declaration and a singleton class

Posted by Trienco on 01 April 2012 - 01:54 AM

Note the first line, you need to forward declaring there.


That's useless. A forward declaration simply says "a class of that name exists somewhere". It will NOT actually let you use that class, because the class is still undefined and it is completely unknown what is IN that class.

A forward declaration let's you do pretty much nothing but pass around pointers/references to that class. You still can't declare a variable of that type (because the size is unknown) and you can't call any functions of it (because they don't exist without actually DEFINING the class and what it looks like).

The simple matter of fact is that you can't "use" a forward declared class.

Fixing dependencies like that is usually based on NOT dumping your implementation in the header file, though in this case as SiCrane already said: DEFINE the class, before you try to use it.


#4926875 Smart pointers question

Posted by Trienco on 30 March 2012 - 11:32 PM

Basically have a single look-up table to see if the item is not deleted everytime you use it, like overriding the '->' operator. That way the ObjectFactory could still track the Gameobjects.


I see a tiny flaw in your concept. What is -> supposed to do if the object WAS deleted? Return 0, automatically have it dereferenced and crash? Or "secretly" redirect your call to a "null object" that simply does nothing?

I see only three scenarios.

a) You say "as long as anybody is still using that object, I must not delete it" -> use shared_ptr... you can still always remove it from whoever manages it, but you delay destruction until the user is done with it

b) You say "it is safe to assume by the time I clean up my table, nobody should be using that pointer anymore". In that case, use raw pointers or unique_ptr/auto_ptr (to clean up automatically when you remove the table)

c) You argue that "the user code should always make sure the pointer is still valid before using it". Use a single shared_ptr for the table and deal out weak_ptr to whoever uses it.

Or wrap it up in a way that returns a null object, if you really and absolutely don't want users to check the pointer. IF you can say "I don't care about nothing happening in that case. It still beats having to check the pointer every single time".

However, in a multi threaded situation (where objects might be used in more than one thread) I would always go with shared_ptr. Simply checking before use is worthless, when the object could be destroyed right between checking and using.


#4925523 Moving to a Point on a Circle

Posted by Trienco on 26 March 2012 - 10:13 PM

Uhm... maybe I'm missing something, but what exactly would be wrong with not putting up with any angles at all? There seems to be an unhealthy obsession with trigonometry where nobody needs it. (Also, all those confusing if's make my head hurt.. math for the most part doesn't generally doesn't work that way).

Look at what you're doing. You already KNOW the vector and instead of simply scaling it to the right length, you bash the problem with the trig club to calculate angles you then use to calculate a shorter version of that same vector. That is simply overcomplicating the problem with a pointless detour.

const Vector3 directionToCam = (Cam - Selected).normalize();
return Selected + (directionToCam * MaxDistance);


//If you really want to be on a circle (not a sphere):
//However keep in mind that if you move it to that position, you will no longer be centered on the object.

Vector3 directionToCam(Cam.x - Selected.x, 0, Cam.z - Selected.z);
Vector3 Calculated = Selected + (directionToCam.normalize() * MaxDistance);
Calculated.y = Cam.y;
return Calculated;



#4924911 OpenGL DrawArrays acting strangely

Posted by Trienco on 24 March 2012 - 10:27 AM

A (x or y) coordinate isn't a vertex and a quad only has 4 vertices. Why are you passing 8?


#4922175 Calculating CPU usage

Posted by Trienco on 14 March 2012 - 11:25 PM

I don't get it. Maybe my world view of how programs are executed is outdated on modern machines. Process is allowed to be executed by scheduler, process runs at CPU clock speed. They don't run faster or slower because "they use a lot of CPU". IPS also seems like a pointless concept. A div takes more cycles than an add. Does that mean a program using lots of divs executing for the same amount of time is using up less CPU, because you get much lower IPS?

You could use a clock that allows measuring actual process or even thread time (not sure what the equivalent is for Windows). A normal timer would not just tell you "this code was giving up its time slice more often or spent more time in blocking operations" it will also tell you "there might have been more higher priority processes active at the time or the scheduler simply had a bad day".

In the same way, stopping how long your code is executing only works for small parts of code and with multiple test runs (or by using a clock that only counts actual time spent in this thread). By just stopping the total time, you would also measure all the time spent in totally different processes whenever the scheduler interrupts you. As an alternative, you could set your thread to realtime priority, but you better make very sure you have a way of ending it and don't get stuck in some loop (or it's reset time).


#4920858 Confused a bit on the matrix math in 3D programming

Posted by Trienco on 10 March 2012 - 02:36 AM

Every object has a world matrix. This matrix is also very simple to read, because the four columns are nothing but "right","up","forward","position".

If you pretend that the camera is a regular object with a world matrix, the view matrix is simply the inverse of it. There is no "camera" and no way to actually change your point of view, You just move everything the opposite way.

Every object that is rendered will go through the view matrix, its world matrix and the projection matrix (or rather one single matrix you get by multiplying them all). 3D is nothing but taking 3D points, putting them through a bunch of matrices and getting a 2D point in screen coordinates. Simply speaking and ignoring all the extra stuff that makes 3D look cool and fancy.


#4919989 unique_ptr and fstream constructor problem

Posted by Trienco on 06 March 2012 - 11:42 PM

Somewhat hard/impossible to tell without seeing if your constructor ever bothers to actually assign an fstream in the first place. I also have absolutely no idea why you believe it necessary to use a different fstream in the first place. If open fails, just call open again WITHOUT ios::in.


#4919854 Message dispatching system - big problem with polymorphism

Posted by Trienco on 06 March 2012 - 12:37 PM

There's a way by using typeid/type_info and a map, which essentially boils down to map<type_info, handlerFunction>. While the implementation isn't overly pretty, the usage looks clean, for example

eventSystem.register(handlerFunction);

Using templates, the type of the handled event is automatically determined (because it's the parameter of the handler function). You will however not be able to use handler functions for any base classes, ie. you can't say handlerFunction(BaseMessage*) and have it handle all kinds of types. typeid will always compare the actual types.

In combination with boost::bind or a selfmade replacement it should work just fine.

You probably don't want to use it as is, because only one function per event type is kind of silly. You can use a multimap instead and the unregister function will require to pass the actual function you want to remove. Also, a function to remove all handler functions that are members of a specific object might be helpful.

Also, this code is mostly based on code I found online. I can't figure out where, but googling for TypeInfo wrapper events tells me that quite a few people used the same source...

class TypeInfo
{
public:
    explicit TypeInfo(const type_info& info) : _typeInfo(info) {}

    bool operator < (const TypeInfo& rhs) const    {
        return _typeInfo.before(rhs._typeInfo) != 0;
    }

private:
    const type_info& _typeInfo;
};

class Event
{
protected:
    Event() {}
    virtual ~Event() {}
};

class HandlerFunctionBase
{
public:
    virtual ~HandlerFunctionBase() {}
    void exec(const Event& event) {call(event);}

private:
    virtual void call(const Event&) = 0;
};

template < class T, class EventT >
class MemberFunctionHandler : public HandlerFunctionBase
{
public:
    typedef void (T::*MemberFunc)(const EventT&);
    MemberFunctionHandler(T* instance, MemberFunc memFn) : _instance(instance), _function(memFn) {}

    void call(const Event& event) { (_instance->*_function)(static_cast< const EventT& >(event)); }

private:
  T* _instance;
  MemberFunc _function;
};

template < class EventT >
class StaticFunctionHandler : public HandlerFunctionBase
{
public:
    typedef void (*Func)(const EventT&);
    StaticFunctionHandler(Func Fn) : _function(Fn) {}

    void call(const Event& event) { _function(static_cast< const EventT& >(event)); }

private:
  Func _function;
};

class EventHandler
{
public:
    ~EventHandler()
    {
        for ( Handlers::iterator it = _handlers.begin(); it != _handlers.end(); ++it )
            delete it->second;
        _handlers.clear();
    }

    void handleEvent(const Event& event)
    {
        Handlers::iterator it = _handlers.find(TypeInfo(typeid(event)));
        if( it != _handlers.end() )
            it->second->exec(event);
    }

    template < class D, class B, class EventT >
    void registerEventFunc(D* obj, void(B::*memFn)(const EventT&))
    {
        unregisterEventFunc<EventT>();
        _handlers[TypeInfo(typeid(EventT))] = new MemberFunctionHandler< B, EventT >(obj, memFn);
    }

    template < class EventT >
    void registerEventFunc(void(*Fn)(const EventT&))
    {
        unregisterEventFunc<EventT>();
        _handlers[TypeInfo(typeid(EventT))] = new StaticFunctionHandler< EventT >(Fn);
    }

    template <class EventT>
    void unregisterEventFunc()
    {
        Handlers::iterator it = _handlers.find(TypeInfo(typeid(EventT)));
        if( it != _handlers.end() )
        {
            delete it->second;
            _handlers.erase(it);
        }
    }

private:
    typedef std::map< TypeInfo, HandlerFunctionBase* > Handlers;
    Handlers _handlers;
};



#4918499 Attempting to start with OpenGL. Lots of failure

Posted by Trienco on 02 March 2012 - 12:00 AM

Get rid of those lines:

glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 3);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 3);
glfwOpenWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

It's way too easy to specify contradictory hints or something that simply isn't supported by your driver/hardware.


#4917303 Program keeps crashing

Posted by Trienco on 27 February 2012 - 11:38 PM

There are plenty of ways to crash, the most obvious being that you just go and delete an enemy (always the LAST one, no matter which name was entered) and don't seem to bother removing him from the list. Even worse, you don't even delete the enemy at all. This code shouldn't even compile, because you assign a string to a enemy*. Even if it was the correct pointer and you were deleting the enemy, the last line (which should probably be)
p_EnemyKill = 0;


is essentially pointless. pEnemyKill is a local variable, setting it to 0 before the end of the function doesn't do anything and most of all it won't affect ANY of the other pointers (especially the next pointer of the previous enemy). Instead of going on about copies and stuff, I'll just make a simple example:

int a = 5;
int b = a;
b = 6;

Is a now 6, just because b was set to the _value_ of b at first? Of course not.

Removing an entry from the middle of the list requires doing a lot more than that. You need to keep a pointer to the previous element so you can make it point to the element after the one to delete. There are also ways to avoid the special handling of head (which doesn't have a previous entry), but they involve a pointer to pointer and I would stay away from that for now.

There are also examples of code that is needlessly complex and could be shorter, cleaner AND more correct/robust.

 enemy* pFirstEnemy = m_pHead;

         cout << pFirstEnemy->getName() << endl;

         while(pFirstEnemy->getNext() != 0)
         {
                 pFirstEnemy = pFirstEnemy->getNext(); // gets the next object
                 cout << pFirstEnemy->getName() << endl; // returns name

         }


I notice at least two functions like that and you never check if the list is empty and a first element even exists. Once you killed the last enemy, this would crash. There is also no good reason to handle the first element separately like it was special in any way.


         enemy* pEnemy = m_pHead;     

         while(pEnemy)
         {
                 cout << pEnemy->getName() << endl; // returns name
                 pEnemy = pEnemy->getNext(); // gets the next object
         }
I also assume that this is your "list project" where you play with linked lists to understand how they work.. and then never ever do that again when you could just use std::list<Enemy> . Especially since muddling the class with list pointers might be the simple way for this example, but in a "real" class:

a) why would an object care if it is going to be stored in a list? (there might be exceptions, for example for pathfinding, though it would be more likely a prev pointer)
b) what if you decide the object needs to be in more than one list at a time?


#4916109 how to return different types?

Posted by Trienco on 23 February 2012 - 11:43 PM

That looks incredibly messy and like the equivalent of constantly abusing dynamic_casts in C++ to check types. It seems like conceptual nonsense to be "deriving" unrelated things like Person and Errors from one base and introduce the mess of dynamically allocating/deallocating objects (especially after all the wild brute force casting) to implement the misguided idea of a single function returning completely different types of objects. Sometimes the question isn't "how can I do this", but "why on earth would I WANT to do this".

Either do what tons of C libraries do and have functions always return an error code while using an output parameter for your data, which will look like this

Person person;
Error error = parseXML(xml, &person);


or return a (well defined) dummy Person on error and set a global error object (C typically does both, with functions returning -1 on error and additionally setting the global error number, a completely separate function will then map error codes to error strings). Of course a global error has other problems of its own (not thread safe, the next call might overwrite your previous error, etc.)

In C++ you could use exceptions for errors, which makes some things very convenient (if your calls go through several levels, you don't have a dozen places to do error checking), but also a little messy (you need to learn writing exception safe code and all the try/catch can go a little out of hand).


#4914454 Putting data into a char* or std::string

Posted by Trienco on 19 February 2012 - 01:23 AM

Ok, I will simply assume that you do NOT want to convert your data into an actual string and have int x = 20 turn into char* = "20".

So first, your function is rather pointless and doesn't do anything that brute force casting your data to char* wouldn't do (without blowing up the stack with a ridiculously large array and pointless copying).

Second, even if this WOULD be working, you at no point seem to terminate that pseudo string you create with a 0. Trying to concatenate it with a string will just keep reading and copying until it hits the first zero that happens to be in memory. Best case: access violation to let you know there is a problem, worst case: seems to work most of the time and in debug builds, but suddenly sometimes breaks or copies garbage.

Third: please don't abuse the string class like that. If you want nothing but a generic buffer for data, use vector<uint8_t>. Anybody seeing "string" expects it to contain actual text, not raw binary data (also, most of the functions of string don't make any sense or will just break in a thousand ways).

The ugly way to do it quick and dirty would be something like:

buffer.insert( buffer.end(), (char*)&MyData, ((char*)&MyData) + sizeof(MyData) );

Now this contains lots of ugly code, should also use a reinterpret_cast<char*>(&MyData), probably be split over 2 lines and it will still break if you use it on anything but native types (ie. do NOT try to use it on c-strings or arrays or stl containers). Yes, it could be used for structs, but if you try to use it to pass data to another program it can break (since you can't rely on it having the same layout in memory). Pragma pack should be looked at. Also byte order if using different platforms. It will also fail hard if your struct contains pointers or anything that requires more than a shallow copy.

While this might look a little cleaner, I would still consider it a case of "please only do this if you really know what you're doing":
const char* rawPtr = reinterpret_cast<const char*>(&MyData);
buffer.insert( buffer.end(), rawPtr, rawPtr + sizeof(MyData) );


You can use templates to hide it and save some work, but should be very careful to have specializations for some types (strings, pointers, arrays) and think REALLY hard about what happens if someone uses this on classes with virtual functions, containing stl containers, etc.

The real question might be: what exactly are you trying to do and what do you need that buffer for?


#4911184 what is capable to do a compter scientist?

Posted by Trienco on 08 February 2012 - 11:13 PM

To quote what we were told A LOT at university: computer scientists are NOT programmers (in fact, some people couldn't have coded their way out of a paper bag and still finished with decent grades.. in the theoretical and technical branches)


#4879149 What heuristic should i use for A* ?

Posted by Trienco on 31 October 2011 - 11:36 PM

If I have two admissible heuristics (less than the true cost), does using the more detailed heuristic (absolute distance) provide any benefit over the coarser heuristic (manhattan distance)? The more detailed heuristic returns different results when the coarser heuristic returns the same results.



The key is to use the best heuristic that doesn't overestimate the actual cost. If your heuristic tends to drastically underestimate you can end up expanding tons of useless nodes, so the closer your heuristic to the actual cost, the faster A* might find your solution.

You can also overestimate on purpose to get a result faster, but once your heuristic overestimates, you might not get the shortest path. That's not always a real problem, because personally, I had 3 options to walk to work every day and no, I never bothered to find out which one might be a few steps longer. So in some cases overestimating a little can even be a good thing.


#4877055 PyRun_SimpleFile(fp, "Test.py") problem

Posted by Trienco on 25 October 2011 - 11:02 PM

Apparently someones Google skills are lacking, considering that took about 10s to find and looks like a good match...

http://effbot.org/pyfaq/pyrun-simplefile-crashes-on-windows-but-not-on-unix-why.htm




PARTNERS