0

I have a txt file with league, teams and players which looks like this :

League: some league

Team:  some team

some players with name and strength

League: some other league

Now i read in the data with my readin function

#include "ReadIn.h"
#include "Player.h"
#include <deque>
#include <fstream>
#include <string>
#include <sstream>
#include <memory>
#include <iostream>


std::string zeile,word1, word2, sname, lname;
std::deque<Team*> Teamvector;
int str, a = 0, b = 0 , c = 0;
using namespace std;

void readin_fillVector(std::deque<Team> &v, std::deque<League> & w, std::vector<Player> u) {
    ifstream fin("C:\\Users\\david\\Documents\\Visual Studio 2013\\Projects\\Anstoss2014\\Datenbank\\test.txt");

    //Einlesen der Zeilen starten
    while (getline(fin, zeile))
    {

        fin >> word1;
        //find out if this line contains the team name or the players
        if (word1 == "Liga:"){
            getline(fin, word2);
            //deleting the empty space in front of the team name
            word2.erase(0, 1);
            w.push_back(League(word2, c));
            c++;
        }
        else if (word1 == "Verein:"){
            getline(fin, word2);
            //deleting the empty space in front of the team name
            word2.erase(0, 1);
            v.push_back(Team(word2, a));

            //League gets the new member ( the team which was read in the line before)
            w.back().AddTeam(&v.back());
            //Team gets an pointer to the league it plays in
            v.back().SetLeague(&w.back());
            a++;
        }
        else{
            fin >> lname >> str;
            Player* player = new Player();
            player->setinformation_(b, word1, lname, str, &v.back());
            u.push_back(*player);
            v.back().AddPlayer(player);
            //for (size_t f = 0; f < v.back().GetPlayerList().size(); f++)
            //{
            //  v.back().GetPlayerList()[f]->getinformation_();
            //}
            b++;

        }
        
    }

}

This works out like it should, but i'm confused with the line

Player* player = new Player();

I read much about pointers and there was said that this player created by new() should be deleted somehow. So first question is :1. Is this right ?

But if i do this in my function, the player's information stored in the team's playervector is lost.

2.I have boost accessable, should i use something like boost::ptr_vector ?

3.If not, what else could i do to avoid memory leak ?

EDIT:

Another way i tried this was

Player player;
player.setinformation_(b, word1, lname, str, &v.back());
u.push_back(player);
v.back().AddPlayer(&player);

But this ended in the the players having no more information stored when the function returns the teamvector. The output is just cryptic then.

Community
  • 1
  • 1
jimbo999
  • 80
  • 7
  • 2
    This code wont compile, you cant insert a `Player*` in a `std::vector` without dereferecning. Simply get rid off all the pointer. You dont need them. And yes you MUST call `delete` (if you dont use the object anymore) – Sebastian Hoffmann Mar 15 '14 at 17:12
  • i do dereference it and it works, everything is okay there my question is all about deleting this pointers. I have no idea how to do it without pointers, wouldn't that be kind of a circular dependence ? – jimbo999 Mar 15 '14 at 17:14
  • `Player player; vec.push_back(player);` ? – Sebastian Hoffmann Mar 15 '14 at 17:17
  • That does not work out as i need to create many players in the loop and point to them, the only way i managed to do this is by Player* player = new Player(), your way leads pointers pointing to the wrong adresses – jimbo999 Mar 15 '14 at 17:27
  • `std::vector` already manages objects on the heap and is a **dynamic** sized container. As long your vector doesnt run out of scope everything is fine. And btw: It doesnt make ANY difference at all whether you write: `vec.push_back(*ptr);` or `vec.push_back(obj);` in both cases a copy is created. – Sebastian Hoffmann Mar 15 '14 at 17:29
  • I editet my post to show what i already tested, if i understand you right this is the way you suggested me to do it. – jimbo999 Mar 15 '14 at 17:34
  • The problem in this case is `v.back().AddPlayer(&player);` changing it to `v.back().AddPlayer(&u.back());` will probably work, but you should really reconsider your design. – Sebastian Hoffmann Mar 15 '14 at 17:35
  • This does lead to acces violation errors, thx for your idead but i really dont know how to desing it in another way that's why i asked ;) – jimbo999 Mar 15 '14 at 17:41
  • @jimbo999 Welcome to C++ where user defined have value semantics. Use smart-pointers for anything else. Storing pointers in containers is rarer and most useful for (virtual) polymorphism. Which is already rarer in C++ too. – sehe Mar 15 '14 at 22:15

1 Answers1

2

Firstly, you are passing in your std::vector<Player> by value. You probably meant to pass it in by reference otherwise any changes you make to it will be lost.

Regarding your specific question, your 'Another way' looks nearly right but you are storing a pointer to the local player variable in your teamvector. When the local player goes out of scope this pointer will be left dangling. You need to store a pointer to the copy of player in the player vector because that is what owns the players.

However, as you discovered, even this will not work because when the the player vector is reallocated during a push_back all pointers to the elements of the vector will be invalidated. You could reserve ahead of time all the space you need in the player vector to ensure no reallocation happens but you might not know how much space to reserve. You could use a different STL container like a std::list which promises that pointers will not be invalidated. But if you don't want to compromise on your choice of container I suggest you create your player objects on the heap and use smart pointers to manage the memory, either std::shared_ptr or std::unique_ptr. So the function prototype would look like:

in_fillVector(std::deque<Team> &v, std::deque<League> & w, std::vector<std::unique_ptr<Player>> &u) 

And adding the players would look like:

auto player = std::unique_ptr<Player>(new Player());
player->setinformation_(b, word1, lname, str, &v.back());
v.back().AddPlayer(player.get());
u.push_back(std::move(player));
Chris Drew
  • 14,926
  • 3
  • 34
  • 54
  • The problem remains the same, after returing the vectors the player in the teamvector have no information left – jimbo999 Mar 16 '14 at 17:47
  • Okay, i found out the reason, it's because the players are created in a loop so adding new Players will change the memory adress of the one's added earlier. std::deque works, but that is not what i want because i need to delete players from every position of the container – jimbo999 Mar 16 '14 at 18:00
  • Ah, @jimbo999, you are right! If the vector is reallocated during a push_back all pointers, references or iterators are invalidated. See [this](http://stackoverflow.com/questions/3329956/do-stl-iterators-guarantee-validity-after-collection-was-changed) and [this](http://www.sgi.com/tech/stl/Vector.html). Looks like I need to edit my answer... – Chris Drew Mar 16 '14 at 18:25
  • @jimbo999 removal of elements from the middle of std::vector is linear time just like std::deque. std::list supports constant time removal from the middle but might not be what you want for other reasons. – Chris Drew Mar 16 '14 at 19:56
  • i read that you CAN'T delete element from the middle of deque, just from the end or the beginning. Is this right ? – jimbo999 Mar 16 '14 at 20:28
  • std::deque::erase can delete elements from the middle of the deque although that WILL invalidate all pointers to the deque. – Chris Drew Mar 16 '14 at 20:34
  • Okay thx for your help that clarified a lot to me, will go on i a new question ;) – jimbo999 Mar 16 '14 at 20:49