I am currently working on a project that deals with a vector of objects of a People class. The program compiles and runs just fine, but when I use the debugger it dies when trying to do anything with the PersonWrangler object. I currently have 3 different classes, one for the person, a personwrangler which handles all of the people collectively, and a game class that handles the game input and output.
Edit: My basic question is to understand why it is dying when it calls outputPeople. Also I would like to understand why my program works exactly as it should unless I use the debugger. The outputPeople function works the way I intended that way.
Edit 2: The callstack has 3 bad calls which are:
std::vector >::begin(this=0xbaadf00d)
std::vector >::size(this=0xbaadf00d)
PersonWrangler::outputPeople(this=0xbaadf00d)
Relevant code:
class Game
{
public:
Game();
void gameLoop();
void menu();
void setStatus(bool inputStatus);
bool getStatus();
PersonWrangler* hal;
private:
bool status;
};
which calls outputPeople where it promptly dies from a baadf00d error.
void Game::menu()
{
hal->outputPeople();
}
where hal is an object of PersonWrangler type
class PersonWrangler
{
public:
PersonWrangler(int inputStartingNum);
void outputPeople();
vector<Person*> peopleVector;
vector<Person*>::iterator personIterator;
int totalPeople;
};
and the outputPeople function is defined as
void PersonWrangler::outputPeople()
{
int totalConnections = 0;
cout << " Total People:" << peopleVector.size() << endl;
for (unsigned int i = 0;i < peopleVector.size();i++)
{
sort(peopleVector[i]->connectionsVector.begin(),peopleVector[i]->connectionsVector.end());
peopleVector[i]->connectionsVector.erase( unique (peopleVector[i]->connectionsVector.begin(),peopleVector[i]->connectionsVector.end()),peopleVector[i]->connectionsVector.end());
peopleVector[i]->outputPerson();
totalConnections+=peopleVector[i]->connectionsVector.size();
}
cout << "Total connections:" << totalConnections/2 << endl;
}
Where hal is initialized
Game::Game()
{
PersonWrangler* hal = new PersonWrangler(inputStartingNum);
}
0xBAADFOOD is a magic number to alert you to the fact that you're dealing with uninitialized memory. From the stack trace, we see that this in PersonWrangler::outputPeople is invalid. Thus hal doesn't point to a valid PersonWrangler (that is, assuming frame 4 is a call to Game::menu). To resolve this sort of thing yourself, step through the code, starting at Game::Game(), examining Game::hal as you go, to see what might be going wrong.
In Game::Game, hal is a local variable that shadows Game::hal. When Game::Game exits, this hal goes out of scope and leaks memory, while Game::hal remains uninitialized. What you want is:
Game::Game()
{
hal = new PersonWrangler(inputStartingNum);
}
Debuggers fill uninitialized memory with magic numbers to make it easier to spot errors. In a production build, memory isn't filled with anything in particular; the content of uninitialized memory is undefined, and might hold valid values. This is why a production build might not fail when a debug build will.
Did you initialize hal to point to an actual PersonWrangler object?
Creating a pointer does not point it at an actual object unless you do it explicitly. You probably want to either pass a PersonWrangler to your Game at construction time, or have the Game constructor create a PersonWrangler using new. If you choose the latter, make sure to delete your PersonWrangler somewhere, probably in the Game deconstructor.
Related
So, my problem is that i want to modify my parent class Board from a derived class in such a way that it applies to all other objects of the derived class. Ex. If I input a 3 on getTest() in players[1] players[2] will be able to print that same value. Is this posible?
class Board {
public:
int test;
virtual void getTest() = 0;
};
class Player : public Board{
public:
int playerNum;
Player(int _playerNum){
playerNum = _playerNum;
}
void printTest(){
cout << "The value of test is: " << Board::test;
}
void getTest(){
cin >> Board::test;
}
};
int main(){
Player players[] = {1,2};
players[1].getTest();
players[0].printTest();
return 0;
}
It is indeed possible to share state between all instances that derive from Board.
As mentioned in the comments, if Board::test were given the static storage-class duration, this would be a variable shared across all instances of Player and any other classes that derive from Board now and forever. Technically, the variable is actually a member of the type rather than instances of the type. This will work, however in terms of design, it has some strange implications.
Namely, Player::getTest() is a non-static member-function, which sets static state that will be shared across all derived classes of Board. This can work as a quick and dirty change to code, but can lead to maintenance burdens and cognitive overhead. For example, if you have code in different subsystems like a Player and Widget that both implement Board, you get into a case where:
// subsystem A:
player.getState();
// subsystem B:
widget.printTest(); // not obvious that this comes from the player in "subsystem A"
The bigger the code gets, the harder it is to understand.
Additionally, static variables have issues working across translation units that can lead to initialization-order problems -- and it's often a mess that's not worth fighting with.
Depending on what it is you actually intend to share, often times it can be better for design to explicitly state as such using an object that explicitly indicates its shared ownership -- such as a std::shared_ptr.
This won't be implicitly passed to everything as you originally requested -- but that's actually a good thing since you can explicitly state what data you want shared and where. This also lets you decide if ever there's a case where you don't want everything shared between them, you can design it as such.
A simple example with your current code would instead be done like:
class Board {
public:
virtual void getTest() = 0;
};
class Player : public Board{
public:
int playerNum;
std::shared_ptr<int> test;
Player(int _playerNum, std::shared_ptr<int> _test){
playerNum = _playerNum;
test = _test;
}
void printTest(){
cout << "The value of test is: " << *test;
}
void getTest(){
cin >> *test;
}
};
int main(){
std::shared_ptr<int> test = std::make_shared<int>(0);
// explicitly share 'test' between the two players
Player players[] = {Player{1,test}, Player{2,test}};
players[1].getTest();
players[0].printTest();
return 0;
}
This would produce the same results as you originally requested, but it explicitly shared test rather than implicitly doing this behind static variables.
Explicitly stating the shared state here also allows you to produce more Player objects later that might share a different set of test state than the first created ones (depending on what this state is, this can be quite useful).
Overall, it's often better in terms of design for readability and overall cognitive overhead to be explicit about the data you want shared.
As far as I know each created object has its own address, and each object's method also has its own address. I want to verify that with the following idea:
Step 1: Build class A with public method, its name is "method".
Step 2: Create two objects in class A, they are object "b" and object "c".
Step 3: Access the addresses of "b.method" and "c.method" to check that they are equal by using a function pointer.
But I met the problem in step 3 and have found every way to solve but failed.
So I posted up here to ask people to help me how to verify what I said above. Thanks everyone!
And here is my C++ code:
#include<iostream>
using namespace std;
class A
{
public:
int a;
void method()
{
//do something
}
static void (*fptr)();
};
int main()
{
A b, c;
A::fptr= &(b.method); //error: cannot convert 'A::method' from type
// 'void(A::)()' to type 'void (*)()'
cout << A::fptr << endl;
A::fptr= &(c.method); //error: cannot convert 'A::method' from type
//'void(A::)()' to type 'void (*)()'
cout << A::fptr << endl;
return 0;
}
Member functions are not like typical functions. The main difference is the way they are called (they have an implicit this argument), but that difference is enough for the language to demand a new way of defining pointers to them. See here for more details.
The following code prints the address in memory of a method:
#include <iostream>
class A {
public:
void method() {
}
};
int main() {
auto ptr = &A::method;
std::cout << reinterpret_cast<void*>(ptr) << "\n";
return 0;
}
As you can see, I had to cast the pointer to a void* to fool the compiler. G++ prints out a warning on that line, but otherwise does what you want with it.
Notice that the type of ptr is void (A::*)(), i.e. "a pointer to a method in A that receives no arguments and returns void". A pointer to methods in your B and C may be slightly different. They should convert to pointers to A, so you might want to go through that when comparing (or just cast to void* and ignore the warning).
Edited to add:
It seems no cast is needed for comparison. You can just directly compare the two pointers to methods, and they will return true or false correctly.
Thank you everyone!
I've been wondering about this for a long time, and now I've figured out the answer myself, there's only one "method()" that's created on memory, even if there are hundreds of objects created. All objects created that want to use this method will have to find the address of this method. Here is the code to prove what I said:
#include<iostream>
using namespace std;
class A
{
public:
int a;
void method()
{
//do something
}
static void (*fptr)();
};
int main()
{
A b,c;
if(&(b.method)==&(c.method))
{
cout<<"they are same\n";
}
else
{
cout<<"they are not same\n";
}
return 0;
}
The compiler and linker does not have to give distinct functions, distinct implementations.
On at least some platforms, the compiler will spot that 2 functions have the same implementation, and merge the 2 functions into a single piece of code. That limits the amount of bloat added by the template system, but stops it being a guaranteed behavior to identify different member functions.
The compiler can
inline all the examples of a single piece of code, and the result is it doesn't have an address.
share implementations where the code is the same.
create multiple implementations of the same function if it thinks it can be done faster.
When C++ was invented, there was a lot of effort to ensure that a C++ compilation unit was able to call a C compilation unit, and the result of this effort, was that many items of the C++ implementation became visible using compatibility tricks.
The C++ pointer to member function had no backwards-compatibility baggage, and thus no reason to allow it to be inspected. As such it is an opaque item, which can be implemented in multiple ways.
In your example there is only one copy of the method in memory. But i cannot think of any easy way to verify that. You can make thousands of objects and see the memory consumption. You can explore the memory occupied by your object in debugger. The memory consumption may be affected by operating system strategy for assigning memory to process. You can also explore disassembly at https://gcc.godbolt.org/
Relevant start for you would be https://godbolt.org/g/emRYQy
I am debugging an issue where there is a seg fault when trying to call push_back to a vector. The seg fault is on the first attempt to add anything to the vector. For debug purposes, I printed out capacity and size before this first attempt, and the result is size: 529486, and capacity: 0.
The frustrating part is that this is an add-on vector, following the same formula used to work with other vectors, and those work. The size and capacity behave as expected with these other vectors.
As rough pseudo-code for what I am doing:
class NEWTYPE{
public:
Object* objPtr;
NEWTYPE();
void update(float );
void setObject(Object* o);
};
class ABCD{
std::vector<TYPE1*> type1List;
std::vector<TYPE2*> type2List;
std::vector<TYPE3*> type3List;
std::vector<TYPE4*> type4List;
std::vector<TYPE5*> type5List; // <== there were 5 other vectors working
std::vector<NEWTYPE*> NEWTYPEList;
}
void ABCD::addType1(TYPE1* n){
cout << type1List.size() << type1List.capacity; // <== as expected
type1List.push_back(n); // <== Works for each old type
}
void ABCD::addNewType(NEWTYPE* n){
cout << NEWTYPEList.size() << NEWTYPEList.capacity; // size: 529486, capacity:0 before first call
NEWTYPEList.push_back(n); // <== seg fault
}
ABCD instance;
// foo() : This procedure works correctly for the other vectors
void foo(){
NEWTYPE* test;
test = new NEWTYPE();
instance.addNewType(test);
}
I am not quite at a point to try to extract things to reproduce in a simple test case. That is one of my next steps.
Anyway, if anyone can point me in the right direction on this, I appreciate the advice. Thanks!
In my case, this turned out to be a build-related issue.
I updated the "master class" (ABCD in the pseudocode) to add the new vector. However, the file that declared the instance was not being rebuilt. The push_back function call was called for a vector that did not exist.
FYI...sorry for not being clear on my original question. Since I was using the same procedures as working parts of the code, my line of thinking was that I may have violated some stack constraint, or exceeded some default setting for vector related to how many vectors were being used.
Garbage returned by std::vector::capacity() and std::vector::size() most probably point to an uninitialized object. As object in your example is global I suspect function foo called from another global object constructor. As order of initialization of global objects is not defined you can have different behavior with different instances of vectors. Possible solution - use singleton object with a local static object:
ABCD &getInstance()
{
static ABCD theInstance;
return theInstance;
}
this way theInstance will be initialized when function getInstance() is called first time. This method does not solve issue with destructor order though, you should design your program the way that destrutcors of global objects should not call methods of other global objects, or use different singleton type (for example phoenix).
Coming from Java to C++ I'm attempting to understand abstraction through object orientation.
To put this into a practical example, I am developing a small game using the SFML library for graphics. However this question does not relate to that, simply think of it as background info. Anyway, the way the game works is to process through a number of different states. In this case 2:
The Menu State: The menu of the game is drawn and the game will begin here.
The Game State: This state controls the game, will update entities and draw them.
In order to do this I have created the following classes:
GameStateManager.h
#ifndef GAMESTATEMANAGER_H
#define GAMESTATEMANAGER_H
#include <SFML/Graphics.hpp>
#include <iostream>
#include "GameState.h"
class GameStateManager
{
public:
// Constructor
GameStateManager();
// State variables
static const int NUMGAMESTATES = 2;
static const int MENUSTATE = 0;
static const int GAMESTATE = 1;
// Public Functions
void set_state(int state);
void update();
void draw(sf::RenderWindow &win);
void input(sf::Event event);
private:
// Array of gamestates
GameState game_states[];
// The current state
int current_state;
// Private functions
void load_state(int state);
void unload_state(int state);
};
#endif
GameState.h
#ifndef GAMESTATE_H
#define GAMESTATE_H
#include <iostream>
#include <SFML/Graphics.hpp>
#include "GameStateManager.h"
class GameState
{
protected:
GameStateManager gsm;
public:
virtual void init() = 0;
virtual void update() = 0;
virtual void draw(sf::RenderWindow &win) = 0;
virtual void input(sf::Event event) = 0;
};
#endif
Now you may have noticed the Array of GameStates in Game State Manager? This provides an error to which I do not understand: zero-sized array. Does this mean initialization needs to be made within the header file? Further to this point the compiler mentions an Array of Abstract class isn't allowed?
The second issue is that the field gsm in the abstract GameState class does not recognize and brings up yet another error: Missing type specifier.
Now to complicate things further I have the following class: MenuState. This class is meant to extend GameState.
MenuState.h
#ifndef MENUSTATE_H
#define MENUSTATE_H
#include "GameState.h"
class MenuState: public GameState
{
public:
MenuState(GameStateManager gsm);
void init();
void update();
void draw(sf::RenderWindow &win);
void input(sf::Event event);
private:
sf::Texture title_texture;
sf::Sprite title_sprite;
};
#endif
As mentioned this class will control the menu of the game.
Implementing GameStateManager is done as follows:
GameStateManager.cpp
/*
* GameState Manager will take care of the various states of the game.
* In particular there will be two states: Menu or Ingame. GameStateManager
* will load and unload each state as needed.
*
* Author: Ben Euden
* Date: 2/5/2014
*/
#include "GameStateManager.h"
// Class Constructor
GameStateManager::GameStateManager()
{
game_states = game_states[NUMGAMESTATES];
current_state = MENUSTATE;
load_state(current_state);
}
/*
* Load the current game by creating and initialising the state
* then storing it in the game_states array.
* #Param state The state we wish to load.
*/
void GameStateManager::load_state(int state)
{
if(state == MENUSTATE)
game_states[state] = MenuState(this);
//if(state == GAMESTATE)
//game_states[state] = MainGameState(this); // Not implemented yet.
}
/*
* Unload the state we loaded with load_state
*/
void GameStateManager::unload_state(int state)
{
game_states[state] = NULL;
}
void GameStateManager::set_state(int state)
{
unload_state(state);
current_state = state;
load_state(state);
}
void GameStateManager::update()
{
try{
game_states[current_state].update();
}
catch(int e)
{
std::cout << "Exception occured during update of game state" << e << std::endl;
}
}
void GameStateManager::draw(sf::RenderWindow &win)
{
try{
game_states[current_state].draw(&win);
}
catch(int e)
{
std::cout << "Exception occured when trying to draw gamestate: " << current_state << "Exception number: " << e << std::endl;
}
}
void GameStateManager::input(sf::Event event)
{
game_states[current_state].input(event);
}
And MenuState as follows:
/*
* This class extends the Game State header and will deal with the menu of the game
* this includes drawing the correct text to the screen, moving the selector and
* either exiting, bringing up about or starting the game.
*
* Author: Ben Euden
* Date: 2/5/2014
*/
#include "MenuState.h"
MenuState::MenuState(GameStateManager gsm)
{
gsm = gsm;
init();
}
void MenuState::init()
{
title_texture = sf::Texture();
title_texture.loadFromFile("sprites/Title.png");
title_sprite = sf::Sprite();
title_sprite.setTexture(title_texture);
title_sprite.setPosition(512, 200);
}
void MenuState::update(){}
void MenuState::draw(sf::RenderWindow &win)
{
win.draw(title_sprite);
}
void MenuState::input(sf::Event event)
{
}
Please ignore inplemented methods and positionings. At this point I began to attempt to compile the project (I'm using Visual Studio) when the errors appeared.
Now in understand that the MainGameState hasn't been implemented yet but even with MenuState I'm sure I'm missing something vital here as I am still learning C++. With this in mind also please excuse any breakage of conventions etc again I am learning so feel free to correct me, it is better I learn the right way now rather than develop bad habits.
In Summary I'd like to understand why I am receiving the following errors:
protected:
GameStateManager gsm;
This produces the error: missing ';' before gsm.
GameState game_states[];
Produces the errors of: zero-size array, array of abstract class not allowed.
I believe if I fix these the rest will sort themselves out.
Thank you for your patience, time and assistance with this.
Euden
To be short: you don't know any basics of C++, and as a beginner, you should really aproach it as a totally different language than Java or C, so you should stop your project right now and find a good book for C++ beginners. Don't try to mix your Java knowledge and just fill the gaps to reach C++ knowledge, it will not work because even if the syntaxe is close, they are widely different beasts.
I always recommend learning C++ as a new and different language, whatever your background. Right now you are doing big errors that shows you're on the wrong path to learn C++. You should get back to basic tutorials (I'm not trying to be harsh, you really need to learn the basics before even managing to compile this code).
You use of arrays and members like if they were references shows your lack of understanding of "value semantic" and several other basic concepts which are must-known of C++ usage.
For example, if I have
class A
{
int k = 42; // C++11
};
Here a A object will contain a k object. What I mean is that k is not a pointer to an int, it's the actual value, within memory allocated into the A object.
So if I have
A my_object; // object on the stack
Then my_object is an object taking the size of an int. So if I do:
class B
{
int u;
A a;
};
Then an instance of B will actually be the size of a A object, plus the size of an int. B objects will contain all these data in a single block of memory.
So when you do:
class GameState
{
protected:
GameStateManager gsm;
What you actually do here is that you build a full GameStateManager into any GameState object. Yes, gsm is not a reference, it's the full object.
What you should do here is either use a c++ reference (if the game manager should never change) or use a pointer (or a smart poitner if there is ownership involved).
I see a lot of other problems, like your array member into GameStateManager have absolutely not the same meaning than in Java. Basically, you're note coding in C++ here. (and you should use either std::vector or std::array but your GameState are dynamic so it would vector or array of pointers - or even map or another container).
As there is too much to point, I should get to the core point:
Whatever the language that you have learnt before, even C or Java which are related, never ever assume you know anything of C++ yet, you absolutely don't. You need to approach it as a beginner. Learn it as a very new language.
And make sure you read actually good material as the list provided there. It's extremely easy to learn bad practice online about C++, unfortunately (but it gets better).
Also, you might want to read this: https://softwareengineering.stackexchange.com/questions/76675/how-can-a-java-programmer-make-the-most-of-a-new-project-in-c-or-c/76695#76695
By the way, a related recommendation: read "SFML Game Development" book for example of simpler and safer (and C++-idiomatic) ways to do what you are trying to achieve here.
Another side recommendation would be to avoid using "manager" in your type names, it only makes things hard to understand and design.
The "zero-size array" error is caused by GameState game_states[];.
In C++ you have to specify the array size at declaration time, either by specifically writing the size or direct initializing it.
Example:
GameState game_states[ ]; // Error, compiler can't know how much memory to reserve for this.
GameState game_states[4]; // OK, explicit size given, compiler will reserve enough memory for 4 `GameState` objects.
GameState game_states[ ] = { GameState( ), GameState( ) }; // OK, direct initialization, compiler will reserve enough memory for 2 `GameState` object.
In your case it should be:
GameState game_states[ NUMGAMESTATES ];
And you should drop the following line from GameStateManager constructor:
game_states = game_states[NUMGAMESTATES]; // Meaningless in C++.
"Array of Abstract class isn't allowed" arises from this declaration also, the problem is C++ differs from Java here. In C++ this declares a variable which is a GameState instance, which is not allowed because GameState has pure virtual methods and as so can't be instantiated ( Just as Java abstract classes can't be newed ). To achieve this polymorphic behavior in C++ you have to use pointers or references, which is what Java uses implicit for you.
Fixing this should give you:
GameState * game_states[ NUMGAMESTATES ];
"missing ';' before gsm" is happening just because the compiler couldn't compile GameStateManager, fixing the bugs I mentioned should solve this.
Few tips:
Think of variables in C++ as ints from Java, even for types you've declared yourself. Which means they are instantiated just by declaring then ( no new needed ) and they are copied when assigned to another variable. ( no reference semantics by default as Java )
Look for good C++ books/tutorials as you don't seem to understand some very important basic concepts from C++.
So I am new to c++ and I'm writing for a scientific application.
Data needs to be read in from a few input text files.
At the moment I am storing these input variables in an object. (lets call it inputObj).
Is it right that I have to pass this "inputObj" around all my objects now. It seems like it has just become a complicated version of global variables. So I think I may be missing the point of OOP.
I have created a g++ compilable small example of my program:
#include<iostream>
class InputObj{
// this is the class that gets all the data
public:
void getInputs() {
a = 1;
b = 2;
};
int a;
int b;
};
class ExtraSolver{
//some of the work may be done in here
public:
void doSomething(InputObj* io) {
eA = io->a;
eB = io->b;
int something2 = eA+eB;
std::cout<<something2<<std::endl;
};
private:
int eA;
int eB;
};
class MainSolver{
// I have most things happening from here
public:
void start() {
//get inputs;
inputObj_ = new InputObj();
inputObj_ -> getInputs();
myA = inputObj_->a;
myB = inputObj_->b;
//do some solve:
int something = myA*myB;
//do some extrasolve
extraSolver_ = new ExtraSolver();
extraSolver_ -> doSomething(inputObj_);
};
private:
InputObj* inputObj_;
ExtraSolver* extraSolver_;
int myA;
int myB;
};
int main() {
MainSolver mainSolver;
mainSolver.start();
}
Summary of question: A lot of my objects need to use the same variables. Is my implementation the correct way of achieving this.
Don't use classes when functions will do fine.
Don't use dynamic allocation using new when automatic storage will work fine.
Here's how you could write it:
#include<iostream>
struct inputs {
int a;
int b;
};
inputs getInputs() {
return { 1, 2 };
}
void doSomething(inputs i) {
int something2 = i.a + i.b;
std::cout << something2 << std::endl;
}
int main() {
//get inputs;
inputs my_inputs = getInputs();
//do some solve:
int something = my_inputs.a * my_inputs.b;
//do some extrasolve
doSomething(my_inputs);
}
I'll recommend reading a good book: The Definitive C++ Book Guide and List
my answer would be based off your comment
"Yea I still haven't got the feel for passing objects around to each other, when it is essentially global variables im looking for "
so this 'feel for passing object' will come with practice ^^, but i think it's important to remember some of the reasons why we have OO,
the goal (in it simplified version) is to modularise your code so as increase the reuse segment of code.
you can create several InputObj without redefining or reassignig them each time
another goal is data hiding by encapsulation,
sometimes we don't want a variable to get changed by another function, and we don't want to expose those variable globally to protect their internal state.
for instance, if a and b in your InputObj where global variable declared and initialized at the beginning of your code, can you be certain that there value doesn't get changed at any given time unless you want to ? for simple program yes.. but as your program scale so does the chances of your variable to get inadvertently changed (hence some random unexpected behavior)
also there if you want the initial state of a and b to be preserved , you will have to do it yourself ( more temp global variables? )
you get more control over the flow of your code by adding level abstractions with classes/inheritances/operation overriding/polymorphisms/Abtract and interface and a bunch of other concepts that makes our life easier to build complex architectures.
now while many consider global variable to be evil, i think they are good and useful when used properly... otherwise is the best way to shoot yourself in the foot.
I hope this helped a bit to clear out that uneasy feeling for passing out objects :)
Is using your approach good or not strongly depends on situation.
If you need some high speed calculation you can't provide incapsulation methods for your InputObj class, though they are recommended, because it will strongly reduce speed of calculation.
However there are two rules that your can follow to reduce bugs:
1) Carefully using 'const' keyword every time you really don't want your object to modify:
void doSomething(InputObj * io) -> void doSomething(const InputObj * io)
2) Moving every action related with initial state of the object(in your case, as far as I can guess, your InputObj is loaded from file and thus without this file loading is useless) to constructor:
Instead of:
InputObj() { }
void getInputs(String filename) {
//reading a,b from file
};
use:
InputObj(String filename) {
//reading a,b from file
};
You are right that this way you have implemented global variables, but I would call your approach structured, and not complicated, as you encapsulate your global values in an object. This will make your program more maintainable, as global values are not spread all over the place.
You can make this even nicer by implementing the global object as a singleton (http://en.wikipedia.org/wiki/Singleton_pattern) thus ensuring there is only one global object.
Further, access the object through a static member or function. That way you don't need to pass it around as a variable, but any part of your program can easily access it.
You should be aware that a global object like this will e.g. not work well in a multithreaded application, but I understand that this not the case.
You should also be aware that there is a lot of discussions if you should use a singleton for this kind of stuff or not. Search SO or the net for "C++ singleton vs. global static object"