Fundamental Pointer Problems - C++

Started by
29 comments, last by _the_phantom_ 16 years, 3 months ago
I'm new to C++ so I'm not sure if what I'm doing is the flat out wrong way of doing this or not. I made a header file that contains all of the code that generates a map for my game. Here are the first few lines...
[[MapGen.h]]
void MapGen()
{
	int MapSize = 0;
	int * P_MapSize = &MapSize
	int MapSize_ResourceVar = 0;
In my main chunk of code for the game, I have this (.cpp file):
#include "MapGen.h"
...
void Population_Start()
{
	MapGen ();
	int Lands = 0;
	int Population = 0;
	Lands = &MapSize / 4;
	Population = Lands;  //grr... define lands in MapGen().  Need pointers to work :)
	int Gold = 100;
	int * P_Gold = &Gold
}
Why is the compiler telling me that &MapSize is undefined? As you can probably guess, it does the same thing for &Gold in other functions etc.
Advertisement
Because the pointers are local variables in the functions you are writing. In example when you call MapGen() it creates all the variables does whatever it does with them, and then when the function is done they are all destroyed.
MapSize is a local variable of the function MapGen(), so it cannot be seen outside of that function (in fact, when the function exits the variable no longer exists and is recreated when the function is called again). Same goes for Gold - it can only be seen inside of Population_Start().

Also, writing:
Lands = &MapSize / 4;

is wrong - you are dividing an address by 4, which doesn't really make sense. I think you meant to leave out the '&'.

One other thing - you should declare and initialize your variables at the same time, so instead of writing:

int a;// Somewhere latera = 5;


you would write:

int a = 5;



This will reduce the chance of the variable being used before it was initialized and will cut down on the code size (which is always nice [smile]). Alongside that, you should declare your variables when you need them and not at the start of a function. Besides also preventing the above, it makes it easier to read the code because the variable appears near the place that it is used.
Thanks for the tips!

Ahh... just checked out the scope of variables at cplusplus.com. I thought that I could treat anything I defined as a pointer as a global variable--big mistake (didn't know they would be deleted when the function ended).

Thanks again.
Remember that space for local variables is allocated on the stack. Once a function exits, the memory where its local variables were stored will probably be overwritten by something else on the next function call.

So you could get a pointer to a local variable, but the memory that the pointer points to won't contain valid data after the function exits and another function is called.

Try the code below to see what I mean:
#include <iostream>using namespace std;/* this function returns a pointer to its local variable */int *set_val(int val){        int i = val;        cout << "i = " << i << endl;        return &i}int main(void){        int *foo, bar;        foo = set_val(42);        bar = *foo;        cout << "bar = " << bar << endl;        /* previous call to cout wrote over the memory foo points to */        bar = *foo;        cout << "bar = " << bar << endl;        return 0;}

On my system, this prints out:
i = 42bar = 42bar = 134519616
Quote:Original post by nibbuler
Ahh... just checked out the scope of variables at cplusplus.com. I thought that I could treat anything I defined as a pointer as a global variable--big mistake (didn't know they would be deleted when the function ended).


I'm guessing you are probably getting confused with pointers and allocated memory.

void f(){    int *i=new int[200];}


After f() exits, the memory allocated still exists, but the pointer i is deleted, so you have no way of accessing the memory or freeing it.

int *f(){    int *i=new int[200];    return i;}void g(){    int *ptr=f();    // do stuff    delete [] ptr;}


Here you are returning a copy of i before it is destroyed, so you can access the memory.

However, all of the above are typical examples of the potential problems with using pointers directly in C++ and why you should almost always prefer to use standard library containers or smart pointers instead.

std::vector<int> f(){    return std::vector<int>(200);}void g(){    std::vector<int> v=f();    // do stuff}


The above is very hard to break, and is unlikely to have any significant performance penalties. Even the apparent additional copy of the vector when being returned is likely to be optimised away by the compiler.
Quote:Original post by nibbuler
Thanks for the tips!

Ahh... just checked out the scope of variables at cplusplus.com. I thought that I could treat anything I defined as a pointer as a global variable--big mistake (didn't know they would be deleted when the function ended).

Thanks again.


Careful there. The concept of "deletion" is totally irrelevant here. First off, the 'delete' keyword only applies to things that were dynamically allocated (using 'new'), and then it's the pointed-at thing that actually gets "deleted", not the pointer itself. Second, "lifetime" (how long the data is in memory) is a different concept from "scope" (the region of the code in which a given name is understood as referring to the variable).

Quote:Original post by EasilyConfused
The above is very hard to break, and is unlikely to have any significant performance penalties. Even the apparent additional copy of the vector when being returned is likely to be optimised away by the compiler.


You hope. Unless the function is inlined, I don't see how the compiler can avoid the copy.

Personally for something like that I'd prefer passing a reference or pointer to an existing vector and filling it in the function:

void f(std::vector<int>& v){    v.clear();    v.resize(200);}void g(){    std::vector<int> v;    f(v);    // do stuff}
Quote:Original post by Jerax
You hope. Unless the function is inlined, I don't see how the compiler can avoid the copy.

Actually, some compilers can use RVO (return value optimization) or NRVO (named return value optimization) in the absence of inlining to eliminate copies. This will be compiler dependent. For instance, see this article about NRVO in MSVC 2005.
Quote:Original post by Jerax
Personally for something like that I'd prefer passing a reference or pointer to an existing vector and filling it in the function:


Therefore creating an empty vector, calling the clear() method, then resizing it, all of which you can again only hope the compiler will optimise away. Given that your function might take an empty vector, or an existing vector with data that needs destructing prior to the resize, the chances of this being optimised out are far lower than the RVOs and NRVOs which are well documented parts of the standard that allow the compiler to alter program flow (i.e. remove a copy constructor).

In the case of

std::vector<int> v=f();


the compiler knows that v is empty prior to being filled with the data returned from f(). Having this information puts the compiler in a far better position to optimise.

And interestingly, in the article SiCrane has referred to, MS state that they implement NRVO by the use of a hidden reference parameter to the function, so the under-the-hood code becomes essentially identicle to your example, but with the additional information available to the compiler that the returned-to object is not an existing object containing data.

[EDIT] Actually, I've just realised that a lot of what I said above is nonsense, since the return result from f() could equally be being assigned to an existing vector.

Sorry.

I guess this optimisation is of less benefit over Jerax's explicit reference passing than I thought.

[Edited by - EasilyConfused on January 2, 2008 2:56:25 PM]

This topic is closed to new replies.

Advertisement