• Hey, guest user. Hope you're enjoying NeoGAF! Have you considered registering for an account? Come join us and add your take to the daily discourse.

C++ Help?

Status
Not open for further replies.

The Technomancer

card-carrying scientician
maharg said:
Sorry, it should be (*it)->Sprite. And yes, it's because the iterator acts like (or is) a pointer and then your value is a pointer.

I hope you're being careful about memory management with this vector, btw. You might want to consider using a shared_ptr as your storage type in the vector.
Hm, I've never heard of a shared_ptr before. I'll look it up, but any tips on how it works?
And yeah, I'm trying to be careful about memory management. I know that I can't just use the erase function since that will leave the object behind in memory (right?) so I'm being careful.
 

maharg

idspispopd
It's a reference counting smart pointer. You'd have your vector be:

Code:
std::vector<std::shared_ptr<SolidObject> >

And it would mostly work as if you had a normal pointer in there, but it would free it when erased. You allocate it the same way and everything.

You might need to use std::tr1::shared_ptr, and if you're using an old version of a C++ compiler it might not be there at all. It was added in the TR1 update to the C++98 standard, which came out about 4 years ago. GCC and VC since then should both have it.
 

The Technomancer

card-carrying scientician
maharg said:
It's a reference counting smart pointer. You'd have your vector be:

Code:
std::vector<std::shared_ptr<SolidObject> >

And it would mostly work as if you had a normal pointer in there, but it would free it when erased. You allocate it the same way and everything.

You might need to use std::tr1::shared_ptr, and if you're using an old version of a C++ compiler it might not be there at all. It was added in the TR1 update to the C++98 standard, which came out about 4 years ago. GCC and VC since then should both have it.
Hm, not sure if I'm understanding. So if I have twenty objects then I store them in a vector of twenty separate shared_ptrs, and if I call erase on one of those shared_ptrs then it also frees the memory of the object itself?
 

maharg

idspispopd
Yes. Assuming you don't copy the shared_ptr for that element out somewhere else, which would hold another reference to it open. Hence, reference counting. When the count goes to 0, the object is freed. In the meantime, you access it just like a normal pointer with * and ->.
 

The Technomancer

card-carrying scientician
maharg said:
Yes. Assuming you don't copy the shared_ptr for that element out somewhere else, which would hold another reference to it open. Hence, reference counting. When the count goes to 0, the object is freed. In the meantime, you access it just like a normal pointer with * and ->.
Oh I like that. Thanks.

Only problem now is that it broke this:
Code:
void System::GenerateBricks(std::vector<std::shared_ptr<SolidObject>> &Immobile){
	for(int i = 0; i <5; i++){
		for(int j = 0; j<4; j++){
			Immobile.push_back(new SolidBrick(600+(50*j), 25+(150*i)));
		}
	}

}
so I'm currently working through that.
 

maharg

idspispopd
Depending on the age of your compiler, you may need to put spaces between the two >s on the right hand side of that typename. This is because the original spec for the tokenizing of C++ made it interpret that as the >> operator.
 

The Technomancer

card-carrying scientician
maharg said:
Depending on the age of your compiler, you may need to put spaces between the two >s on the right hand side of that typename. This is because the original spec for the tokenizing of C++ made it interpret that as the >> operator.
Hm, I'm working in the latest version of VC++, but I'll try it.

EDIT: Nope.
 

The Technomancer

card-carrying scientician
Hmm...
Code:
error C2664: 'void std::vector<_Ty>::push_back(_Ty &&)' : cannot convert parameter 1 from 'SolidBrick *' to 'std::tr1::shared_ptr<_Ty> &&'
1>          with
1>          [
1>              _Ty=std::tr1::shared_ptr<SolidObject>
1>          ]
1>          and
1>          [
1>              _Ty=SolidObject
1>          ]
1>          Reason: cannot convert from 'SolidBrick *' to 'std::tr1::shared_ptr<_Ty>'
1>          with
1>          [
1>              _Ty=SolidObject
1>          ]
1>          Constructor for class 'std::tr1::shared_ptr<_Ty>' is declared 'explicit'
1>          with
1>          [
1>              _Ty=SolidObject
1>          ]
I tried experimentally making a new shared_ptr and a few other things, no luck.
 

fenners

Member
The_Technomancer said:
Hmm...
I tried experimentally making a new shared_ptr and a few other things, no luck.


shared_ptrs are cool, but it's running before you can walk, IMO, if you're not feeling confident with basic ptrs.
 

The Technomancer

card-carrying scientician
fenners said:
shared_ptrs are cool, but it's running before you can walk, IMO, if you're not feeling confident with basic ptrs.
Eh, ever since I figured out the interaction between pointers and -> I feel a lot better about using them honestly.
 

poweld

Member
Try:
Code:
Immobile.push_back(shared_ptr(new SolidBrick(600+(50*j), 25+(150*i))));

You're trying to append a pointer to a SolidBrick into a vector containing shared_ptr<SolidBrick> and there is no implicit conversion for this.
 

maharg

idspispopd
fenners said:
shared_ptrs are cool, but it's running before you can walk, IMO, if you're not feeling confident with basic ptrs.

Ugh. Smart pointers are not an advanced feature. Anyone who thinks that a managed pointer with explicit ownership policies that keeps you from shooting yourself in the foot is MORE advanced than raw pointers ... I don't even know where to begin with this. Insanity.

Smart pointers make your code clearer, are easier to use, and catch errors at compile time instead of runtime. They should absolutely be C++ 101, especially now that there are several useful ones in the standard.

And yes, what he said in the post above mine. Sorry for not making that clearer. Unfortunately the one side effect of the standard library is it can make your code a little ridiculously verbose at times. Can't wait for 'auto' to be widespread (not that that helps this case, but it does help other much worse offenders).
 

Chichikov

Member
maharg said:
Ugh. Smart pointers are not an advanced feature. Anyone who thinks that a managed pointer with explicit ownership policies that keeps you from shooting yourself in the foot is MORE advanced than raw pointers ... I don't even know where to begin with this. Insanity.

Smart pointers make your code clearer, are easier to use, and catch errors at compile time instead of runtime. They should absolutely be C++ 101, especially now that there are several useful ones in the standard.

And yes, what he said in the post above mine. Sorry for not making that clearer. Unfortunately the one side effect of the standard library is it can make your code a little ridiculously verbose at times. Can't wait for 'auto' to be widespread.
I agree with most of what you said, but shared_ptr is probably not the best introduction to the concept.

Also fenners is absolutely right that you should not tackle smart pointers until your're comfortable with pointers.
 

maharg

idspispopd
Why would you say that? It's by far the most general purpose of any smart pointer. It's the one you should consider using first. It also maps most closely to the ownership model of normal pointers.

Now auto_ptr, there's a frightening introduction.

And no, fenners is absolutely wrong. There is no good reason for people to learn raw pointers before smart pointers whatsoever. And I'm saying this as someone who's been programming in the language for almost 20 years and remembers a time when the very concept of a smart pointer was basically a pipe dream.

The right way to learn C++ in 2011 is to take full advantage of the standard library and learn the lower level concepts later. Unless you have a very specific interest in the lower levels. Anything else just leads to an assumption that premature optimization is a good idea.
 

The Technomancer

card-carrying scientician
Chichikov said:
I agree with most of what you said, but shared_ptr is probably not the best introduction to the concept.
Well I don't really see the conceptual problems with shared_ptr outside of some of the specific syntax in getting it to interact with other things. The idea of a pointer system that automatically frees memory once there are no more references to the pointed object seems straightforward and nice. What other pointer types are there?
 

Chichikov

Member
maharg said:
Why would you say that? It's by far the most general purpose of any smart pointer. It's the one you should consider using first. It also maps most closely to the ownership model of normal pointers.
I always believed that reference counting is something that should be used sparingly, and only where it's really needed.
Plus it uses a lot of (relatively) advanced syntax and constructs that can be a bit scary to a coding neophyte.

maharg said:
Now auto_ptr, there's a frightening introduction.
You don't think RAII should be in programming 101 in this day and age?


maharg said:
And no, fenners is absolutely wrong. There is no good reason for people to learn raw pointers before smart pointers whatsoever.
I STRONGLY disagree.
I think that using smart pointers without understanding pointers is asking for troubles. troubles you won't know how to solve.

That being said, I'm not sure an argument about the best way to learn c++ is the most exciting way we both can spend time on the internet, so we can just agree to disagree or something.
 

maharg

idspispopd
Chichikov said:
I always believed that reference counting is something that should be used sparingly, and only where it's really needed.
Plus it uses a lot of (relatively) advanced syntax and constructs that can be a bit scary to a coding neophyte.

To the first, a shared_ptr should not be used where a reference will do to be sure, but one of the fundamental concepts people need to learn in C++ is ownership policies and how they impact these choices. Telling people that their first choice should be a raw pointer is essentially giving them permission to abdicate their responsibility to communicate effectively about the ownership and lifecycle of an object.

And if references are used properly, the number of reference count changes a shared_ptr is going to go through will be quite low, even if I wasn't going to point out that this concern has premature optimization written all over it. If refcount changes on a relatively rarely copied object are a big problem for you, you'd better be writing the rendering loop of a game (and even then I highly doubt you'd be mashing reference counts all that much during the hot path).

As for syntax, if you can't handle object initialization syntax or a template parameter, I'm not sure you're cut out for C++. Do you think no one should use vector until they've hit their first delete vs. delete[] bug, just because it takes a template parameter? No, that's just silly. People should be using vector<> for the same reasons they should be using smart pointers, including shared_ptr.

You don't think RAII should be in programming 101 in this day and age?

You do realize that shared_ptr is RAII, right? You are *acquiring* an ownership (or, with weak_ptr, a non-ownership) reference to an object. And then when that reference is destroyed, so is the acquired ownership.

Also vector, string, etc. Also RAII. You did notice I said the *whole* C++ standard library, right?

Anyways, no. That's not why I think auto_ptr is something people shouldn't be taught first, in terms of smart pointers. I think that because its semantics lead to hard to find runtime bugs that are *real* problems for newbie programmers. In particular, the copy constructor is destructive on its rhs, and this can happen in places people might not think about (ie. the copy constructor of a containing object. Or a vector being sorted).

C++0x is deprecating auto_ptr in favour of unique_ptr, which doesn't have this problem (you can only copy it from an rvalue, which is safe).
 

The Technomancer

card-carrying scientician
My knowledge of pointers is pretty rudimentary, but then again I think they are rudimentary, aren't they? They're literally just addresses. When I had the workings of a linked list or how to use one as an iterator through something like a vector explained to me I got the concept straight away.
My main issues so far have been learning all the specific syntax and how it interacts (the various different contexts for . :: and ->). Still not entirely comfortable with double pointers, but I haven't worked with them much.
 

poweld

Member
While I agree that reference counting is like mana from heaven, I also see some validity to working with and deeply understanding raw pointers before using reference counting. My reasoning is that without experiencing the hardships that one is bound to encounter using raw pointers, they may not fully understand why reference counting is a boon, and I for one hate being told "do this because it's correct". Learning the hard way, when it's not life-threatening, can be an educational experience.

The_Technomancer said:
My knowledge of pointers is pretty rudimentary, but then again I think they are rudimentary, aren't they? They're literally just addresses. When I had the workings of a linked list or how to use one as an iterator through something like a vector explained to me I got the concept straight away.
My main issues so far have been learning all the specific syntax and how it interacts (the various different contexts for . :: and ->). Still not entirely comfortable with double pointers, but I haven't worked with them much.
Maybe I can help you on your quest to conquering pointers:
Like you said, a pointer's value is just a location in memory. When we are dealing with a double (or triple, etc) pointer, we are declaring that the address of the double pointer is where we will find yet another pointer. This second pointer, in turn, locates the data type we are expecting.

For example:
Code:
int (argc, char** argv) { ... }
I'm sure you've seen this before. argc and argv are working in tandem to provide a useful structure. We know that argv is a pointer to a pointer to a char, or in other words, a pointer to a string.

Code:
argv (char**)---+
                |
                v
             char *
                |
                v
       char,char,...,NULL
However, we are only able to assume that there are multiple characters strung together to make a string because we know that (char)0 is the NULL character, which marks the end of the string.

What about if argv? Well, it may contain multiple strings in the same way the char* may contain multiple chars. This is where argc comes in. It, quite simply, tells us just how many char* we should expect in argv. In the case where no arguments are passed into the command line, argc will equal 1, containing just the absolute path to the command called.

If argc > 1, we can expect argv to instead look more like this:
Code:
argv (char**)---+------------------+------------------+------- (and so on)
                |                  |                  |
                v                  v                  v
             char *             char *             char *
                |                  |                  |
                v                  v                  v
     char,char,...,NULL   char,char,...,NULL   char,char,...,NULL
Hope this helps.
 

The Technomancer

card-carrying scientician
I think so. Since a pointer to an array is a pointer to the first element of an array, using a double pointer expands the potential dimensions of storage.
 

poweld

Member
The_Technomancer said:
I think so. Since a pointer to an array is a pointer to the first element of an array, using a double pointer expands the potential dimensions of storage.
Yup, exactly, though keep in mind that a "pointer to an array" is really just a pointer to what we are supposing is an array. This is one of the major pitfalls of pointers... while we may think we're pointing to an array of Foo objects, the address that is contained in the pointer could very well be pointing to a singular Bar object, invalid memory, or nothing at all!

Skepticism is your greatest friend when dealing with raw pointers.
 

The Technomancer

card-carrying scientician
Alright, vector question. One of the reasons I'm working with vectors is because of how they handle automatic resizing. However I'm currently running into an issue where I think the problem is that I use the current position of an iterator to vectorname.erase(iterator) an object in the middle of a vector, but that iterator is used in a containing for loop and so when the for loop goes to increment the iterator it can't find it or something? I'm getting a "cannot increment iterator" error.

Any advice?

The relevant code:
Code:
for(std::vector<std::shared_ptr<SolidObject>>::iterator it = Moving.begin(); it != Moving.end(); it++){
		if((*it)->GetType() == 3){
			//std::cout <<"Ball check: OK" << std::endl;
			for(std::vector<std::shared_ptr<SolidObject>>::iterator it2 = Immobile.begin(); it2 !=Immobile.end(); it2++){

//lots of stuff

if(Collision::PixelPerfectTest(((*it)->Sprite), (*it2)->Sprite)){
						//std::cout << "Collision" << std::endl;
						(*it)->Velocity.x = -(*it)->Velocity.x;
                                                Immobile.erase(it2);
					}
                    }
}
 
The_Technomancer said:
Alright, vector question. One of the reasons I'm working with vectors is because of how they handle automatic resizing. However I'm currently running into an issue where I think the problem is that I use the current position of an iterator to vectorname.erase(iterator) an object in the middle of a vector, but that iterator is used in a containing for loop and so when the for loop goes to increment the iterator it can't find it or something? I'm getting a "cannot increment iterator" error.

Any advice?

The relevant code:
Code:
for(std::vector<std::shared_ptr<SolidObject>>::iterator it = Moving.begin(); it != Moving.end(); it++){
		if((*it)->GetType() == 3){
			//std::cout <<"Ball check: OK" << std::endl;
			for(std::vector<std::shared_ptr<SolidObject>>::iterator it2 = Immobile.begin(); it2 !=Immobile.end(); it2++){

//lots of stuff

if(Collision::PixelPerfectTest(((*it)->Sprite), (*it2)->Sprite)){
						//std::cout << "Collision" << std::endl;
						(*it)->Velocity.x = -(*it)->Velocity.x;
                                                Immobile.erase(it2);
					}
                    }
}

Stylistic issues first: The formatting here is atrocious, indentation looks inconsistent, and the code is almost impossible to read. Also, instead of writing std::vector<std::shared_ptr<SolidObject> >::iterator, just use the auto keyword. Much more pleasant. Note that you need Visual Studio 2010 or a recent version of GCC for the auto keyword to work. I've re-written your code, and fixed your issue in the process:


Code:
for(auto it = Moving.begin(); it != Moving.end(); ++it)
{
    if((*it)->GetType() == 3)
    {
        auto it2 = Immobile.begin();
        while (it2 != Immobile.end())
        {
            if(Collision::PixelPerfectTest(((*it)->Sprite), (*it2)->Sprite))
            {
                (*it)->Velocity.x = -(*it)->Velocity.x;
                it2 = Immobile.erase(it2);
            }
            else
                ++it2;
        }
    }
}

Note that I also changed it++ and it2++ to ++it and ++it2. This is important for iterators, as the first version is actually slower.

Note that the solution to the original problem you asked about involves changing the for loop to a while loop, and using the return value of the erase function in case the test passes, and incrementing the iterator if the test does not pass.

Finally, I would point out that GetType() == 3 should be replaced with a comparison against an enumeration, not the number 3. For example:

Code:
enum FooType
{
    kTypeFoo = 1,
    kTypeBar = 2,
    kTypeBaz = 3,
    ...
};

if ((*it)->GetType() == kTypeBaz)
{
}
 

The Technomancer

card-carrying scientician
Thanks. Lots of good advice there. The problem with indentation is that it is consistent in VS, but when I copy-paste it to GAF some stuff gets lost and its a bit hard to visualize how the
tags work.

Also wow, how did I not know about the auto keyword? That saves so much, thanks.​
 

poweld

Member
cpp_is_king said:
Stylistic issues first: The formatting here is atrocious, indentation looks inconsistent, and the code is almost impossible to read. Also, instead of writing std::vector<std::shared_ptr<SolidObject> >::iterator, just use the auto keyword. Much more pleasant. Note that you need Visual Studio 2010 or a recent version of GCC for the auto keyword to work. I've re-written your code, and fixed your issue in the process:


Code:
...

Note that I also changed it++ and it2++ to ++it and ++it2. This is important for iterators, as the first version is actually slower.
I'm not going to tell you that you're wrong, but with normal levels of optimization, this makes zero difference. (citation)
Note that the solution to the original problem you asked about involves changing the for loop to a while loop, and using the return value of the erase function in case the test passes, and incrementing the iterator if the test does not pass.

Finally, I would point out that GetType() == 3 should be replaced with a comparison against an enumeration, not the number 3. For example:
Yes, "magic numbers" are misleading to anybody reading your code, including yourself after just a short amount of time. Enums are a more readable and extensible solution.
Code:
...
I thought I'd explain the most relevant part of this solution, and what was causing your problem. The erase() call restructures the container (vector) beginning at the location you have erased, and continuing through to the end of the container. Any iterators you may have pointing to any of the elements at or after the erased element are invalid once the operation takes place.

As cpp_is_king has shown, the erase() function returns a valid iterator to the next element in the container after the erase is completed, which will either be another valid element, or the end() iterator of the container.
 

maharg

idspispopd
poweld said:
I'm not going to tell you that you're wrong, but with normal levels of optimization, this makes zero difference. (citation)

That article does point out that the story is different with higher order objects, but it's worth pointing out that for vector in particular, the optimized version actually is a pointer, and thus it will have identical performance characteristics to a pointer between pre and post increment.

But, still, this is premature optimization at its best, even with those caveats going both ways.


The_Technomancer said:
Also wow, how did I not know about the auto keyword? That saves so much, thanks.

Because it's new. I did mention it a page or so ago, but I didn't recommend you use it because at present it requires you to use a compiler flag to enable it on gcc, and I wasn't aware of whether or not it had been implemented in VC yet.
 

The Technomancer

card-carrying scientician
maharg said:
That article does point out that the story is different with higher order objects, but it's worth pointing out that for vector in particular, the optimized version actually is a pointer, and thus it will have identical performance characteristics to a pointer between pre and post increment.

But, still, this is premature optimization at its best, even with those caveats going both ways.




Because it's new. I did mention it a page or so ago, but I didn't recommend you use it because at present it requires you to use a compiler flag to enable it on gcc, and I wasn't aware of whether or not it had been implemented in VC yet.
Hm, okay, I'll do some research, thanks. I've learned a lot of minutiae and implementation that I needed to know in the last few days thanks to you guys.

Running into a problem using the enumerator. I set up
Code:
protected:
[INDENT]enum{Ball = 1, Paddle, Brick}[/INDENT]
just fine, but if I want to use those enumerated values in a different .cpp file where do I place them?
 

poweld

Member
The_Technomancer said:
Running into a problem using the enumerator. I set up
Code:
protected:
[INDENT]enum{Ball = 1, Paddle, Brick}[/INDENT]
just fine, but if I want to use those enumerated values in a different .cpp file where do I place them?
Why not in the SolidObject class? If you want to access it from another .cpp, just #include the SolidObject header file. If you're accessing it from outside the class, you will also have to specify the class namespace:
Code:
SolidObject::Ball
...in which case you'd also have to make the enum public instead of protected, unless the outside class accessing it is derived from SolidObject.
 

The Technomancer

card-carrying scientician
Slightly more abstract question this time. Say I have the following code
Code:
while(x){
[INDENT]while(y){[/INDENT]
[INDENT][INDENT]//stuff goes here[/INDENT][/INDENT]
[INDENT]}[/INDENT]
}

If x becomes false but y remains true will I break free?
 

Lathentar

Looking for Pants
The_Technomancer said:
Slightly more abstract question this time. Say I have the following code
Code:
while(x){
[INDENT]while(y){[/INDENT]
[INDENT][INDENT]//stuff goes here[/INDENT][/INDENT]
[INDENT]}[/INDENT]
}

If x becomes false but y remains true will I break free?
No. When it is inside the while(y) loop it will only check the condition y, not x. You have to do x && y.
 

The Technomancer

card-carrying scientician
Okay, enumerators are pissing me off. I stick something simple like
enum{up = 0, left, down, right}; at the top of a .h file, but when I try to use those terms in any file that includes that .h I get an error "'Left' is undefined"
 

Zoe

Member
The_Technomancer said:
Okay, enumerators are pissing me off. I stick something simple like
enum{up = 0, left, down, right}; at the top of a .h file, but when I try to use those terms in any file that includes that .h I get an error "'Left' is undefined"

What's the name of your enum?
 

fenners

Member
Zoe said:
What's the name of your enum?

And mind, if the enum is defined inside a class or namespace, you need to use that too,e.g.

Code:
class SomeClass
{
     enum Blah
    {
         eFoo
     };
};


SomeClass::eFoo
 

maharg

idspispopd
The name just gives it a type, it doesn't affect how you access it. There's a thing in C++0x for scoped enums, but I don't think it's implemented in the wild yet (or if it is, it's very recent versions of gcc).
 

The Technomancer

card-carrying scientician
maharg said:
The name just gives it a type, it doesn't affect how you access it. There's a thing in C++0x for scoped enums, but I don't think it's implemented in the wild yet (or if it is, it's very recent versions of gcc).
A type? Can enumerators be types other then int? As for where I'm placing it I'm not sticking it inside the class definition itself, I'm just appending it at the top of the header.
 

wolfmat

Confirmed Asshole
The_Technomancer said:
A type? Can enumerators be types other then int?
Not a native type; an abstract type that is defined by its name and structure. Enum values are always int. Enums themselves are of the type that is defined wholly by the name you gave the enum, and you can reference them by name.

Like, this enum is of type foo:
Code:
enum foo {
   DICK,
   JUNK
};

This enum is an unnamed type:
Code:
enum {
   JACK = 19,
   JOHN = 2000
};
 

The Technomancer

card-carrying scientician
wolfmat said:
Not a native type; an abstract type that is defined by its name and structure. Enum values are always int. Enums themselves are of the type that is defined wholly by the name you gave the enum, and you can reference them by name.

Like, this enum is of type foo:
Code:
enum foo {
   DICK = 1,
   JUNK = 2
};

This enum is an unnamed type:
Code:
enum {
   JACK = 1,
   JOHN = 2
};
Okay, sweet, so say that I have that foo enum that you show off there. How do I access its symbols? Currently I have the second example in one of my header files, but when I try to use JOHN in a .cpp file that includes that header I get an error.
 

wolfmat

Confirmed Asshole
Well, if it's defined inside of a class, you need to make sure it is in scope when it is referenced. So the enum has to be in public for outside code to be able to refer to it.
If it is outside of a class, it is in the global namespace and should thus be referrable from anywhere.

If you could post both the definition of your enum and show the scope, and then post how you refer to it, that would be helpful.

By the way, enums should get their own namespaces so that you don't pollute the global namespace. Just so you know.
 

The Technomancer

card-carrying scientician
The header file:
Code:
#include<SFML\Graphics.hpp>

#ifndef _GAMEOBJECT_H
#define _GAMEOBJECT_H

enum{up = 0, left, down, right};

class GameObject{
//stuff

The .cpp file:
Code:
#include"System.h"
#include"GameObject.h"

//a bunch of stuff

void System::Input(sf::RenderWindow &App, PlayerObject &Player, float ETime){
	if (App.GetInput().IsKeyDown(sf::Key::Left))  Player.Move(Left, ETime);
	if (App.GetInput().IsKeyDown(sf::Key::Right))  Player.Move(Right, ETime);

}

Note that sf::Key::Left and Right are not attempting to use the enumerated symbols, those Left and Right are defined inside sf::Key
 

wolfmat

Confirmed Asshole
The_Technomancer said:
The header file:
Code:
#include<SFML\Graphics.hpp>

#ifndef _GAMEOBJECT_H
#define _GAMEOBJECT_H

enum{up = 0, left, down, right};
Name this enum (like, name it MovementDirection). That way, you can use that type in the signature of Player.Move(), instead of using the nondescriptive int you probably have there right now.
As a result, up, left, down and right are also of the type MovementDirection.
The .cpp file:
Code:
#include"System.h"
#include"GameObject.h"

//a bunch of stuff

void System::Input(sf::RenderWindow &App, PlayerObject &Player, float ETime){
	if (App.GetInput().IsKeyDown(sf::Key::Left))  Player.Move(Left, ETime);
	if (App.GetInput().IsKeyDown(sf::Key::Right))  Player.Move(Right, ETime);

}

Note that sf::Key::Left and Right are not attempting to use the enumerated symbols, those Left and Right are defined inside sf::Key
The case in the call of Player.Move() is wrong for both enums. You have it lowercase in the definition, but use uppercase there.
 

The Technomancer

card-carrying scientician
wolfmat said:
Name this enum (like, name it MovementDirection). That way, you can use that type in the signature of Player.Move(), instead of using the nondescriptive int you probably have there right now.
As a result, up, left, down and right are also of the type MovementDirection.

The case in the call of Player.Move() is wrong for both enums. You have it lowercase in the definition, but use uppercase there.
*facepalm*

That would do it. Thanks...

If I name it how does that change interactions? Like...MovementDirection.Left whenever I want to use it?
 

wolfmat

Confirmed Asshole
The_Technomancer said:
*facepalm*

That would do it. Thanks...

If I name it how does that change interactions? Like...MovementDirection.Left whenever I want to use it?
No. Just left still (or Left if you changed it to uppercase in the definition).

See, that's one of the problems with polluting the global namespace. At the very least, you want to use more descriptive enumerators (like MOVEMENT_DIRECTION_LEFT, for instance). Then, you'd also use it like that. In a function that only uses MovementDirection, that is the type of the parameter. When you compare, you compare to the enumerators.
Example:
Code:
move(MovementDirection movementDirection){
   if(movementDirection == MOVEMENT_DIRECTION_LEFT) {
[…]

You could also define a namespace for MovementDirection (something like CharacterMovement or whatever); then, you'd have to refer to that namespace when you want to use the type / one enumerator inside it.
 

Toma

Let me show you through these halls, my friend, where treasures of indie gaming await...
Visual Studio question:

How can I access the window where I can see all the variables currently in use when the program is running? I found it by accident a few days ago but cant find it again.

Edit: Found it! Debug - Windows - Locals
 
maharg said:
That article does point out that the story is different with higher order objects, but it's worth pointing out that for vector in particular, the optimized version actually is a pointer, and thus it will have identical performance characteristics to a pointer between pre and post increment.

But, still, this is premature optimization at its best, even with those caveats going both ways.

It is definitely a premature optimization, but since there is virtually no reason to ever prefer one over the other for any other reason than that just mentioned (in the context of for loop control variable incrementation), why not just always use pre-increment as a rule?

it's especially important when writing a templatized function since the the argument could be anything from an integer to something like a database cursor that runs a db query in its copy constructor. Obviously the person asking this question isn't dealing with this scenario, but the point is - there's no reason to not get in the habit of just always using pre-inc in a for loop.

In fact, might as well extend this "rule" outside of loop variables.

Always use pre-increment, unless you really must have post-increment semantics.

People always use post-inc because it's what's taught first in C++ 101 books. So just pretend you learned pre-inc first, and always use it for everything unless you really must have post-inc. There's no reason not to.
 
Status
Not open for further replies.
Top Bottom