0

I have checked Stack Overflow for a sample of these class vectors and none of the answers point out common uses of vectors in a class . My code works but I have a few questions on it .

I have a struck of objects that is stored in a class member vector

struct Station
{
    std::string StationName;
    int StationId;
    int PlayerId;
    std::vector<float> position;

};

Here is the class that declaration with the Vectors

class playerData
{
public:
    std::vector <playerDataDetails> PlayerList;
    std::vector<Station> Stations;
    void addNewPlayer(std::string Name , std::string faction , int Id );
    void PrintPlayer();
    void AddStations(int PlayerNumber, std::string name);

};

When running the member function this is how Im accessing the Vector

 void playerData::AddStations(int PlayerNumber, std::string name)
{
    // p[i].
     Station s ;
     s.StationName = name;
     s.StationId = 1; 
     s.PlayerId = PlayerNumber;
     s.position = { 2.1f, 1.1f , 1.1f};

    // s.position = { { 2.1f }, { 2.3f }, { 2.3f } };

    

    this->Stations.push_back(s);

 }

My question is this .

this->Stations.push_back(s);

  • Is this the correct way to add station to the stations vector ?
  • Is this copy or move Semantics ?
  • Is there another way of doing this with pointers and references ?
  • And is this the most efficient way of working with Vectors in a class ?
13
  • 1
    This line playerData::Stations ; has no effect. Commented Jul 11, 2022 at 13:35
  • 100% was testing all things out using it including a static call ... Removed it ...
    – JonoJames
    Commented Jul 11, 2022 at 13:37
  • Yes, Copy (but you could also emplace it directly), Yes (std::shared_ptr, unique_ptr, or whatever), opinion-based; For me the biggest issue with your examples is the naming convention. Name YourClasses, yourVariables, and _yourClassMermbers in some unified way.
    – pptaszni
    Commented Jul 11, 2022 at 13:40
  • 1
    Yes it's correct, it's copy semantics, to possibly use move semantics replace push_back with emplace_back. Most efficient is highly subjective. When I was a professional developer most efficient meant least likely to be buggy, most likely to be understood by a future maintenance developer, most robust to future changes etc. Important stuff like that.
    – john
    Commented Jul 11, 2022 at 13:40
  • 1
    s.StationName = name; -- There are multiple (unnecessary) copies of the string going on. The parameter being passed is by value (incurs a copy) here: void playerData::AddStations(int PlayerNumber, std::string name), and then the assignment shown above. Pass the string by const reference, not by value. Commented Jul 11, 2022 at 13:45

1 Answer 1

2

Is this the correct way to add station to the stations vector ?

It's a perfectly fine approach, just a little inefficient.

Is this copy or move Semantics ?

Copy semantics (this->Stations.push_back(s); invokes the version of push_back taking a const reference and copies it into the vector).

Minimalist changes could avoid unnecessary copies by changing s.StationName = name; to s.StationName = std::move(name); and this->Stations.push_back(s); to this->Stations.push_back(std::move(s));, which is enough to replace all copies with moves (though additional changes could reduce the number of moves and potentially eliminate some temporaries).

Is there another way of doing this with pointers and references ?

Yes. Pointers don't help, but more careful use of move semantics and/or emplace* semantics (to avoid temporaries entirely) could improve things (see below).

And is this the most efficient way of working with Vectors in a class ?

No. This could be done far more efficiently by avoiding some unnecessary copies and/or moves.

Without changing Station, you could replace the entire body of AddStations with either:

this->Stations.push_back({std::move(name), 1, PlayerNumber, {2.1f, 1.1f , 1.1f}});

or:

this->Stations.emplace_back(Station{std::move(name), 1, PlayerNumber, {2.1f, 1.1f , 1.1f}});

adding std::move() around name to avoid a copy in favor of a move, and avoiding a copy of Station (it probably still needs to move-construct it into the vector though).

If you defined an explicit constructor for Station, e.g. Station(std::string sn, int sid, int pid, std::vector<float> pos) : StationName{std::move(sn)}, StationId(sid), PlayerId(pid), position(std::move(pos)) {}, you could also use:

this->Stations.emplace_back(std::move(name), 1, PlayerNumber, std::vector<float>{2.1f, 1.1f , 1.1f});

which would definitely avoid a move of a Station object itself (though it still has to move the name and the temporary vector in the process of constructing it directly into the Stations).

The various forms of weirdness in why each form of push_back or emplace_back works, or doesn't, with varying levels of explicitness is explained on this question.

1
  • Great answer I liked the idea of using the explicit constructor with an initialization list as its far cleaner . I will serialize the data into a binary stream so what I was hoping to desterilize it in the following way . std::vector<Station> Stations[4] = { { "A10", 1, 1, std::vector<float>{2.1f, 1.1f , 1.1f}, { "A11", 1, 1, std::vector<float>{2.1f, 1.1f , 1.1f}, { "A12", 1, 1, std::vector<float>{2.1f, 1.1f , 1.1f}, { "A13", 1, 2, std::vector<float>{2.1f, 1.1f , 1.1f} }; but I work around how to do it affectively
    – JonoJames
    Commented Jul 11, 2022 at 18:36

Not the answer you're looking for? Browse other questions tagged or ask your own question.