0

I have the following class:

public:
    Client(tcp::socket socket)
    : socket_(std::move(socket))
    {
    }
    void start();
    int connectionId;

Than I have the following vector:

class Server {
public:
    Server();
    static std::vector<std::shared_ptr<Client>> Clients;
}

EDIT*

Can I do something like this:

for (int i = 0; i < Server::Clients.size(); ++i) {
    if(Server::Clients[i]->connectionId == connectionId)
        Server::Clients.erase(Server::Clients.begin()+i);
}

My question is how can I remove the shared pointer in Clients with a specific connectionId aka remove by value?

Venelin
  • 2,905
  • 7
  • 53
  • 117

3 Answers3

0

In C++17, you can do use std::remove_if. The following should work.

#include <algorithm>

Server &s = /* <getServerFromSomewhere> */;
auto new_end = remove_if(s.Clients.begin(), s.Clients.end(),
    [] (std::shared_ptr<Client>& p) {
        return p->connectionId == /* <someValueToBeRemoved> */;
    }
);
s.Clients.resize(new_end - s.Clients.begin());
lvella
  • 12,754
  • 11
  • 54
  • 106
0

Use std::remove_if with a lambda as predicate and then container's method erase:

std::vector<std::shared_ptr<Client>> Clients;
int id{0}; // the id to be removed
Clients.erase(std::remove_if(Clients.begin(), Clients.end(), [id](const auto &entity) { return id == entity->connectionId; }), Clients.end());
Vasilij
  • 1,861
  • 1
  • 5
  • 9
0

If you don't have access to std::remove_if, you have to fall back to loop of a kind:

auto it = Clients.begin()

while (it != Clients.end())
{
    if((*it)->connectionId = testValue)
    {
         // can connection id be non-unique?
         it = Clients.erase(it);
         //if yes, we have to save new iterator
         continue;
    }
    it++;
}

If connectionId is unique use find_if to find that element and erase it, it's way cheaper.

If remove_if available, following code is possible, if it's advantage over first example is questionable.

auto new_end = remove_if(s.Clients.begin(), s.Clients.end(),
    [=] (auto& ptr) {
        return ptr->connectionId ==  testValue; /* value to be removed */
    }
erase(new_end, Clients.end()); // remove tail of vector that is now consisting of empty elements.

Clients better be a deque than a vector, that way erasing an element from it won't cause the "tail" part of Clients list to be copied when every removal is done.

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42
  • I've added an edit to my question. Can I go as I marked in the question? – Venelin Sep 16 '20 at 12:14
  • 1
    "both remove an element" - No, they don't both remove an element. The vector's size remains **the same** if just using `remove`. There's a reason the idiom is called "erase-remove". – StoryTeller - Unslander Monica Sep 16 '20 at 12:23
  • @StoryTeller-UnslanderMonica he's not doing that, he strangely does in backward loop – Swift - Friday Pie Sep 16 '20 at 12:29
  • No, he *is* doing that. The loop is another oddity, but he did *try* to use the idiom correctly. Saying something like *"why you use both remove_if and erase? Both remove an element"* is wrong and misleading. – StoryTeller - Unslander Monica Sep 16 '20 at 12:31
  • Guys I have updated my question. Can I correctly remove from a vector like I have described in the question? – Venelin Sep 16 '20 at 12:32
  • Plus i've changed my vector to `deque` as @Swift-FridayPie suggested. Seems like operators for adding and removing from `deque` and `vector` are pretty much the same. – Venelin Sep 16 '20 at 12:33
  • @VenelinVasilev the interface is similar, deque got cheaper [] operator than list and cheaper removal than vector. It only doesn't have adjacent memory storages for elements – Swift - Friday Pie Sep 16 '20 at 12:34
  • @StoryTeller-UnslanderMonica sorry, I didn't saw he added second argument to `erase` (or were those consequent edits?). That would be a bug of different kind and a really easy to make mistake. – Swift - Friday Pie Sep 16 '20 at 12:36