C++ unordered_map weird size allocation - c++

I am experimenting with this code with a lockfree programming and running into weird problems.
This is a dinning philosophers problem, and I am trying to implement that in a lockfree way.
I am reserving the size of unordered_map and making sure that it is not relocating objs during runtime. But unfortunately what I see that during runtime size of Philosopher::umap is weirdly assigned, (in example below, I am restricting it to 10, but during runtime it is changing to 30-40). Can someone help me understand what is going on here.
#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <memory>
#include <atomic>
#include <chrono>
#include <tuple>
#include <unordered_map>
class Eater {
public:
virtual void Eating() = 0;
~Eater() {
}
};
class Dreamer {
public:
virtual void Dreaming() = 0;
~Dreamer() {}
};
class Gamer {
public:
virtual void Gaming() = 0;
~Gamer() {
}
};
class Philosopher : public Dreamer, public Eater {
private:
const uint32_t id_;
public:
static std::atomic<uint32_t> gen;
static std::unordered_map<uint32_t, std::tuple<uint32_t, uint32_t>> umap;
Philosopher()
: id_(++gen) {
umap.emplace(id_, std::make_tuple(0,0));
}
Philosopher(const Philosopher& that) : id_(that.id_) {
}
Philosopher(Philosopher&& that) : id_(that.id_) {
}
virtual void Eating() override {
umap[id_] = std::make_tuple(1+std::get<0>(umap[id_]), std::get<1>(umap[id_])); // this is failing - despite, seperate thread working on separate memory location
}
virtual void Dreaming() override {
umap[id_] = std::make_tuple(std::get<0>(umap.at(id_)), 1+std::get<1>(umap.at(id_))); // this is failing - despite, seperate thread working on separate memory location
}
~Philosopher() {
}
};
std::unordered_map<uint32_t, std::tuple<uint32_t, uint32_t>> Philosopher::umap;
std::atomic<uint32_t> Philosopher::gen(0u);
class Engine : public Gamer {
private:
uint32_t m_count_philosophers_;
std::vector<std::shared_ptr<std::thread>> m_vthread_;
public:
Engine(uint32_t n)
: m_count_philosophers_(n) {
m_vthread_.reserve(n);
}
virtual void Gaming() override {
std::atomic<uint32_t> counter(0u);
while(counter++ < m_count_philosophers_) {
m_vthread_.emplace_back(std::make_shared<std::thread>([&]() mutable {
Philosopher philosopher;
std::chrono::duration<double> elapsed_seconds;
auto start = std::chrono::steady_clock::now();
while(elapsed_seconds.count() < 2) {
philosopher.Eating();
philosopher.Dreaming();
auto finish = std::chrono::steady_clock::now();
elapsed_seconds = finish - start;
}
}));
}
for(auto &iter : m_vthread_) {
iter->join();
}
}
};
int main() {
auto N = 10u;
Philosopher::umap.reserve(N); // there are no more than N elements in the unordered_map
Engine eng(N);
eng.Gaming();
for (auto &i : Philosopher::umap)
{
std::cout << "phi: " << i.first << " eating: " << std::get<0>(i.second) << ", dreaming: " << std::get<1>(i.second) << "\n";
}
return 0;
}

Related

Make a collection of an abstract class type, Abstract Class vector of shared_ptr

Error
e/c++/v1/algorithm:642:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/utility:321:9: error:
field type 'Space' is an abstract class
_T2 second;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/map:624:16: note:
Question
How can I define a std::vector of type Space which is an abstract class and then fill this vector with instances of the derived classes Empty, Snake, Ladder.
Context
I know abstract classes in C++ can not be instantiated. Instead I've read in several posts on this and other sites that you can create a collection of an abstract type if it the type is defined as a star * pointer or any of the <memory> managed pointer data types like std::unqiue_ptr<T>. I've tried to used shared_ptr<Space> in my case, but still unable to define the collection properly. I am compiled my code using g++ -std=c++17 main.cpp && ./a.out.
Code
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <map>
#include <memory>
#include <typeinfo>
#include <queue>
#include <string>
#include <vector>
class Player
{
private:
int m_current_space = 1;
public:
Player() {}
void role_dice() {
m_current_space += floor( (rand()%10 + 1) / 3 );
}
int const get_current_space() {
return m_current_space;
}
void set_current_space(int current_space) {
m_current_space = current_space;
}
};
class Space
{
protected:
int m_id;
std::vector<Space> m_paths;
public:
Space() {} // requied to use [] operator in map
Space(int id) : m_id(id) {}
void add_path(Space& s) {
m_paths.push_back(s);
}
int get_id() {
return m_id;
}
virtual std::string class_type() = 0;
};
class Empty : public Space
{
public:
Empty(int id) : Space(id) {}
std::string class_type() {
return "Empty";
}
};
class Ladder : public Space
{
public:
Ladder(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(1);
}
std::string class_type() {
return "Ladder";
}
};
class Snake : public Space
{
public:
Snake(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(4);
}
std::string class_type() {
return "Snake";
}
};
class Board
{
private:
std::map<int, Space> m_board;
public:
void add_space(Space& s) {
m_board[s.get_id()] = s;
}
void draw_board() {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
std::cout << "○\n";
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
std::cout << "○ ";
}
++i;
}
}
void update_player_on_board(int position) {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
if (space_key == position) {
std::cout << "●\n";
}
else {
std::cout << "○\n";
}
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
if (space_key == position) {
std::cout << "● ";
}
else {
std::cout << "○ ";
}
}
++i;
}
}
const std::map<int, Space> get_board() {
return m_board;
}
friend std::ostream &operator<<(std::ostream& os, const Board& b) {
return os;
}
};
class GameStateManager
{
private:
std::string m_state = "game over";
bool m_playing = false;
public:
std::string const get_state() {
return m_state;
}
void set_state(std::string state) {
m_state = state;
}
};
int main()
{
std::cout << "Welcome to Bowser's 9 board game\n";
std::cout << "Start? y(yes) n(no)\n";
GameStateManager game_manager;
game_manager.set_state("playing");
auto space1 = std::make_shared<Space>(1);
auto space2 = std::make_shared<Space>(2);
auto space3 = std::make_shared<Space>(3);
auto space4 = std::make_shared<Space>(4);
auto space5 = std::make_shared<Space>(5);
auto space6 = std::make_shared<Space>(6);
auto space7 = std::make_shared<Space>(7);
auto space8 = std::make_shared<Space>(8);
auto space9 = std::make_shared<Space>(9);
std::vector<std::shared_ptr<Space>> v {
space1, space2, space3,
space4, space5, space6,
space7, space8, space9
};
Board bowsers_bigbad_laddersnake;
for(int i = 0; i < 10; ++i) {
bowsers_bigbad_laddersnake.add_space(*(v[i]));
}
bowsers_bigbad_laddersnake.draw_board();
Player mario;
int turn = 0;
while(game_manager.get_state() == "playing") {
std::cin.get();
std::cout << "-- Turn " << ++turn << " --" << '\n';
mario.role_dice();
bowsers_bigbad_laddersnake.update_player_on_board(mario.get_current_space());
if (mario.get_current_space() >= 9) {
game_manager.set_state("game over");
}
}
std::cout << "Thanks a so much for to playing!\nPress any key to continue . . .\n";
std::cin.get();
return 0;
}
You seem to have removed a lot of code to get into details here.
Have a Space pointer (smart or raw). Instantiate the specific space that you want, point to it with your pointer of type Space. Example std::shared_ptr<Space> pointerToSpace = std::make_shared<Snake> ("I'm a snake"); Now, without loss of generality, you can print the contents (of concrete type) with just the pointer to the space pointerToSpace->class_type(). Yes, you can have a collection of shared_ptrs in a container.

A vector for different classes

I have a class with a vector I'd like to fill with one of two types of class, selected by the user. Let's call my classes option1 and option2
What I'd like to do it something like
class storage_class
{
public:
storage_class(int sel, int n)
{
if(sel == 1)
for(int i = 0; i < n; i++)
my_store.push_back(std::make_unique<option1>());
else if(sel == 2)
for(int i = 0; i < n; i++)
my_store.push_back(std::make_unique<option2>());
}
private:
// Something like this but that actually works
std::vector<T> my_store;
};
Then I'd like to use it like this, or something similar, so there's no need to modify this usage dependent on the option chosen.
int main()
{
storage_class store(1);
int n_iterations = 4;
for(int i = 0; i < n_iterations; i++)
{
store.my_store[i]->create_data();
}
}
The classes option1 and option2 will be mathematical simulations that will be creating data and themselves store this data in a vector that are members of the class.
I want to store multiple instances of either option in a vector and then manipulate them from there. I can use C++17.
As you have c++17 in use, you can simply use a std::variant as type for the container which itself can keep all types you want to have.
Example:
class A { public: void Do() { std::cout << "A::Do" << std::endl; } };
class B { public: void Go() { std::cout << "B::Go" << std::endl; } };
template<class... Ts> struct funcs : Ts... { using Ts::operator()...; };
template<class... Ts> funcs(Ts...) -> funcs<Ts...>;
int main()
{
std::vector<std::variant<A,B>> vec;
vec.push_back(A{});
vec.push_back(B{});
for ( auto& el: vec)
{
std::visit( funcs{ [](A& a){ a.Do(); }, [](B& b) { b.Go(); } }, el);
}
}
Output:
A::Do
B::Go
The classes are fully independent and the methods can be simply called with std::visit and passing a callable object herein. I provide a simple funcs implementation, which simply collect all callable entities to simplify to interface the call to different methods of different unrelated classes here.
As std::variant is some kind of a tagged union, it needs the storage for the biggest type you have in use. If this wastes to much memory, you can store a pointer to the instance instead, maybe with std::unique_ptr or std::shared_ptr if you like some assistance for memory management ;)
Here is an example that tries to stay as close to your example as it can using a template parameter on class storage_class. See working version here. I've added only option1 and made the member my_store public as you access it in your main function.
#include <memory>
#include <vector>
#include <iostream>
struct option1{
void create_data(){ std::cout << "created\n"; }
};
template<typename T>
class storage_class
{
public:
storage_class(int n)
{
for(int i = 0; i < n; i++)
my_store.push_back(std::make_unique<T>());
}
std::vector<std::unique_ptr<T>> my_store;
};
int main()
{
storage_class<option1> store(4);
int n_iterations = 4;
for(int i = 0; i < n_iterations; i++)
{
store.my_store[i]->create_data();
}
}
another option would be to use std::variant. See workign version here.
#include <memory>
#include <vector>
#include <variant>
#include <iostream>
struct option1{
void create_data(){ std::cout << "created 1\n"; }
};
struct option2{
void create_data(){ std::cout << "created 2\n"; }
};
class storage_class
{
public:
using option = std::variant<std::unique_ptr<option1>,std::unique_ptr<option2>>;
storage_class(int sel, int n)
{
if(sel == 0)
for(int i = 0; i < n; i++)
my_store.push_back(option(std::make_unique<option1>()));
else if(sel == 1)
for(int i = 0; i < n; i++)
my_store.push_back(option(std::make_unique<option2>()));
}
std::vector<option> my_store;
};
int main()
{
storage_class store(1, 4);
int n_iterations = 4;
for(int i = 0; i < n_iterations; i++)
{
std::get<1>(store.my_store[i])->create_data();
}
}
Standard way is to make option1 and option2 derived classes from a base_class which seems consistent with your sample main(). Using a generic Factory class template, here is an example:
#include <functional>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <vector>
// Generic Factory class template
template<typename K,typename T,typename... Ts>
class Factory
{
using Map = std::unordered_map<K, std::function<std::unique_ptr<T>(Ts...)>>;
const Map mMap;
public:
Factory(Map&& map):mMap(std::move(map)) { }
std::unique_ptr<T> operator()(const K& key, Ts... args) const
{
const typename Map::const_iterator itr = mMap.find(key);
return itr == mMap.cend() ? nullptr : itr->second(std::forward<Ts>(args)...);
}
};
class base_class
{
public:
virtual void create_data() = 0;
};
class option1 : public base_class
{
public:
void create_data() override
{
std::cout << "I'm option1." << std::endl;
}
};
class option2 : public base_class
{
public:
void create_data() override
{
std::cout << "I'm option2." << std::endl;
}
};
class storage_class
{
using SimulationFactory = Factory<int,base_class>; // Optionally add constructor parameter types
const SimulationFactory simulation_factory; // This can be made static const.
public:
storage_class(int sel, int n)
: simulation_factory(
{ { 1, []() { return std::make_unique<option1>(); } }
, { 2, []() { return std::make_unique<option2>(); } }
})
{
for (int i = 0; i < n; i++)
my_store.push_back(simulation_factory(sel));
}
std::vector<std::unique_ptr<base_class>> my_store;
};
int main()
{
int n_iterations = 4;
storage_class store(1, n_iterations);
for(int i = 0; i < n_iterations; i++)
{
store.my_store[i]->create_data();
}
}
This compiled for me on linux using g++ -std=c++17 main.cc.
There are improvements that can be made to this code, but I copied your main() function in order to illustrate the basic idea(s). Hope that helps.
Edit 21 Sept 2018 - Example of how to pass parameters into constructors.
File: factory.h
#pragma once
#include <functional>
#include <memory>
#include <unordered_map>
// Generic Factory class template
template<typename K,typename T,typename... Ts>
class Factory
{
using Map = std::unordered_map<K, std::function<std::unique_ptr<T>(Ts...)>>;
const Map mMap;
public:
Factory(Map&& map):mMap(std::move(map)) { }
std::unique_ptr<T> operator()(const K& key, Ts... args) const
{
const typename Map::const_iterator itr = mMap.find(key);
return itr == mMap.cend() ? nullptr : itr->second(std::forward<Ts>(args)...);
}
};
File: main.cc
#include "factory.h"
#include <iostream>
#include <string>
#include <vector>
class base_class
{
public:
virtual void create_data() = 0;
};
class option1 : public base_class
{
const double mD;
public:
option1(double d)
: mD(d)
{ }
void create_data() override
{
std::cout << "I'm option1: mD("<<mD<<')' << std::endl;
}
};
class option2 : public base_class
{
const double mD;
public:
option2(double d)
: mD(d)
{ }
void create_data() override
{
std::cout << "I'm option2: mD("<<mD<<')' << std::endl;
}
};
class storage_class
{
using SimulationFactory = Factory<int,base_class,double>; // Optionally add constructor parameter types
const SimulationFactory simulation_factory; // This can be made static const.
public:
storage_class(int sel, int n)
: simulation_factory(
{ { 1, [](double d) { return std::make_unique<option1>(d); } }
, { 2, [](double d) { return std::make_unique<option2>(d); } }
})
{
for (int i = 0; i < n; i++)
my_store.push_back(simulation_factory(sel,static_cast<double>(i)));
}
std::vector<std::unique_ptr<base_class>> my_store;
};
int main()
{
int n_iterations = 4;
storage_class store1(1, n_iterations);
storage_class store2(2, n_iterations);
for(int i = 0; i < n_iterations; i++)
{
store1.my_store[i]->create_data();
store2.my_store[i]->create_data();
}
}
Output:
I'm option1: mD(0)
I'm option2: mD(0)
I'm option1: mD(1)
I'm option2: mD(1)
I'm option1: mD(2)
I'm option2: mD(2)
I'm option1: mD(3)
I'm option2: mD(3)

How to run a function of an actual object, which is stored in the container using OOP?

How to run a function of an actual object, which is stored in the container using OOP?
Background: I'm writing a game. There is a set of 4 interconnected rooms. There are two different room types and two different player types. Players should run as threads. The Killer should have a fight with a normal player in the Action room. In the second type of room, nothing should happen. The game logic and code is simplified.
When the thread starts, void Player::operator()() is being executed. The player enters the room, does his action initializeAction(), and leaves it. In case of a Killer, his initializeAction() leads to room->actionInRoom(*this), which executes player.inActionRoom().
The problem is in this code void Killer::inActionRoom():
std::vector<Player> &playersWithoutKillers = room->getPlayersWithoutKillers();
auto it = playersWithoutKillers.begin();
std::advance(it, 0);
Player chosenPlayerForFight = *it;
...
chosenPlayerForFight.decreasePoints();
where chosenPlayerForFight.decreasePoints(); does not decrease the points for the actual player, but I think it does it for a copy of an object.
If I run the code, this mistake is visible: OtherPlayer's points will always reset to 1. If I'm decreasing it every time the fight occurs, the negative value is expected.
-> Killer in Forth room Killer 11 vs OtherPlayer 1
Starting decreasing points from 1
Ending decreasing points from 0
I tried to fix the code, mainly by making sure the reference of an object is passed.
Main.cpp:
#include <iostream>
#include <memory>
#include <thread>
#include "Room.h"
#include "Player.h"
std::mutex globalMessageMutex;
int main() {
auto first = std::make_shared<RelaxRoom>("First room");
auto second = std::make_shared<ActionRoom>("Second room");
auto third = std::make_shared<RelaxRoom>("Third room");
auto forth = std::make_shared<ActionRoom>("Forth room");
first->setRoomPair(second, forth);
second->setRoomPair(third, first);
third->setRoomPair(forth, second);
forth->setRoomPair(first, third);
std::vector<std::thread> players;
players.emplace_back(OtherPlayer("OtherPlayer", first));
players.emplace_back(Killer("Killer", first));
for (auto &t : players) {
if (t.joinable()) {
t.join();
}
}
return 0;
}
Player.h
#ifndef HW03_PLAYER_H
#define HW03_PLAYER_H
#include <string>
#include <memory>
class Room;
class Player {
friend class Room;
public:
Player(const std::string &playerName, std::shared_ptr<Room> initialTargetRoom);
void operator()();
friend bool operator== ( const Player &lhs, const Player &rhs );
const std::string &getName() const;
virtual void inActionRoom() {};
virtual void inRelaxRoom(Room &pRoom) {};
virtual bool isKiller()const;
virtual bool isOtherPlayer();
int getPoints()const;
void increasePoints();
void decreasePoints();
int points;
protected:
std::shared_ptr<Room> room;
virtual void initializeAction();
private:
std::string name;
std::shared_ptr<Room> initialRoom;
};
class OtherPlayer : public Player {
public:
OtherPlayer(const std::string &playerName, const std::shared_ptr<Room> &initialTargetRoom);
void initializeAction() override;
void inActionRoom() override;
void inRelaxRoom(Room &pRoom) override;
bool isOtherPlayer() override;
};
class Killer : public Player {
public:
Killer(const std::string &playerName, const std::shared_ptr<Room> &initialTargetRoom);
void initializeAction() override;
void inActionRoom() override;
void inRelaxRoom(Room &pRoom) override;
bool isKiller() const override;
};
#endif //HW03_PLAYER_H
Player.cpp
#include <iostream>
#include <chrono>
#include <thread>
#include <random>
#include "Player.h"
#include "Room.h"
extern std::mutex globalMessageMutex;
Player::Player(const std::string &playerName, std::shared_ptr<Room> initialTargetRoom) {
name = playerName;
initialRoom = initialTargetRoom;
room = initialTargetRoom;
points = 1;
}
void Player::operator()() {
room->enter(*this);
initializeAction();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
room->leave(*this);
while (auto nextRoom = room->getNext()) {
room = nextRoom;
nextRoom->enter(*this);
initializeAction();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
nextRoom->leave(*this);
}
}
void Player::initializeAction() {}
bool operator==(const Player &lhs, const Player &rhs) {
return lhs.name == rhs.name;
}
const std::string &Player::getName() const {
return name;
}
bool Player::isKiller() const {
return false;
}
bool Player::isOtherPlayer() {
return false;
}
int Player::getPoints() const {
return points;
}
void Player::increasePoints() {
points++;
}
void Player::decreasePoints() {
std::cout << "Starting decreasing points from " << points << std::endl;
points--;
std::cout << "Ending decreasing points from " << points << std::endl;
}
OtherPlayer::OtherPlayer(const std::string &playerName, const std::shared_ptr<Room> &initialTargetRoom) : Player(playerName,
initialTargetRoom) {}
void OtherPlayer::initializeAction() {
room->actionInRoom(*this);
}
void OtherPlayer::inActionRoom() {}
void OtherPlayer::inRelaxRoom(Room &pRoom) {}
bool OtherPlayer::isOtherPlayer() {
return true;
}
Killer::Killer(const std::string &playerName, const std::shared_ptr<Room> &initialTargetRoom) : Player(playerName,
initialTargetRoom) {}
void Killer::initializeAction() {
room->actionInRoom(*this);
}
void Killer::inActionRoom() {
std::lock_guard<std::mutex> ml(globalMessageMutex);
if (!room->getPlayersWithoutKillers().empty()) {
**std::vector<Player> &playersWithoutKillers = room->getPlayersWithoutKillers();**
**auto it = playersWithoutKillers.begin();
std::advance(it, 0);
Player chosenPlayerForFight = *it;**
auto killersVitality = this->getPoints();
auto othersPlayerPoints = chosenPlayerForFight.getPoints();
std::cout << "-> Killer in " << room->getName() << " " << this->getName() << " " << killersVitality
<< " vs " << chosenPlayerForFight.getName() << " " << othersPlayerPoints << std::endl;
this->increasePoints();
**chosenPlayerForFight.decreasePoints();**
}
}
void Killer::inRelaxRoom(Room &pRoom) {
}
bool Killer::isKiller() const {
return true;
}
Room.h
#ifndef HW03_ROOM_H
#define HW03_ROOM_H
#include <string>
#include <vector>
#include <condition_variable>
class Player;
class Room {
public:
Room(const std::string &roomName);
void setRoomPair(std::shared_ptr<Room> firstRoom, std::shared_ptr<Room> secondRoom);
std::shared_ptr<Room> getNext();
void enter(Player &player);
void leave(Player &player);
virtual void actionInRoom(Player &player)= 0;
const std::string &getName() const;
const std::vector<Player> &getPlayers();
std::vector<Player> &getPlayersWithoutKillers();
protected:
std::string name;
size_t killersCount;
size_t playersWithoutKillersCount;
private:
std::vector<Player> players;
std::vector<Player> playersWithoutKillers;
std::condition_variable cv;
std::mutex mutex;
std::pair<std::shared_ptr<Room>, std::shared_ptr<Room>> roomPair;
void updateCounterPlayerLeaves(Player &player);
void updateCounterPlayerEnters(Player &player);
};
class ActionRoom : public Room {
public:
ActionRoom(const std::string &roomName) : Room(roomName) {}
void actionInRoom(Player &player) override;
};
class RelaxRoom : public Room {
public:
RelaxRoom(const std::string &roomName) : Room(roomName) {}
void actionInRoom(Player &player) override;
};
#endif //HW03_ROOM_H
Room.cpp
#include <iostream>
#include <algorithm>
#include <random>
#include "Room.h"
#include "Player.h"
#include <mutex>
extern std::mutex globalMessageMutex;
Room::Room(const std::string &roomName) {
name = roomName;
}
const std::string &Room::getName() const {
return name;
}
std::shared_ptr<Room> Room::getNext() {
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
std::mt19937 engine(seed);
std::uniform_int_distribution<int> randomGenerator(0, 1);
auto randomNumber = randomGenerator(engine);
if (randomNumber) {
return roomPair.second;
}
return roomPair.first;
}
void Room::enter(Player &player) {
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock, [this, &player] {
return true;
}
);
players.push_back(player);
updateCounterPlayerEnters(player);
std::lock_guard<std::mutex> ml(globalMessageMutex);
std::cout << name << ": killers: " << killersCount << ", other players: " << playersWithoutKillersCount <<
std::endl;
}
void Room::updateCounterPlayerEnters(Player &player) {
if (player.isKiller()) {
killersCount++;
} else {
playersWithoutKillersCount++;
playersWithoutKillers.push_back(player);
}
}
void Room::leave(Player &player) {
{
std::lock_guard<std::mutex> lock(mutex);
auto it = std::find(players.begin(), players.end(), player);
if (it == players.end()) {
return;
}
players.erase(it);
updateCounterPlayerLeaves(player);
}
cv.notify_all();
}
void Room::updateCounterPlayerLeaves(Player &player) {
if (player.isKiller()) {
killersCount--;
} else {
playersWithoutKillersCount--;
auto it = std::find(playersWithoutKillers.begin(), playersWithoutKillers.end(), player);
if (it == playersWithoutKillers.end()) {
return;
}
playersWithoutKillers.erase(it);
}
}
void Room::setRoomPair(std::shared_ptr<Room> firstRoom, std::shared_ptr<Room> secondRoom) {
roomPair.first = std::move(firstRoom);
roomPair.second = std::move(secondRoom);
}
const std::vector<Player> &Room::getPlayers() {
return players;
}
std::vector<Player> &Room::getPlayersWithoutKillers() {
return playersWithoutKillers;
}
void ActionRoom::actionInRoom(Player &player) {
player.inActionRoom();
}
void RelaxRoom::actionInRoom(Player &player) {
player.inRelaxRoom(*this);
}
Not a complete answer, since you said this is a homework assignment.
However, one pattern you can use to solve this problem is to have your container store std::unique_ptr<some_base_class> values, or if necessary std::shared_ptr<some_base_class>, and fill them with pointers to derived objects. For example: container.emplace_back(static_cast<some_base_class*>(new derived_class(foo, bar, baz))); will construct everything in place inside your container, so the compiler doesn’t need to make any temporary copies. You might also write something like:
std::vector<std::unique_ptr<some_base_class>> container;
{
std::unique_ptr<derived_class> temp =
make_unique<derived_class>();
temp->setup( foo, bar, baz );
container.emplace_back(static_cast<some_base_class*>(temp.release()));
// temp is now empty, and the pointer in the container now owns the object.
}
You can use the full interface of some_base_class through these smart pointers, with ->, but if you need to turn them back into references to derived objects, you would use RTTI and dynamic_cast.
There are other approaches, including a discriminated union and std::variant, but storing smart pointers to the base class that defines your interface is what I recommend you try here.

Implementation of static constructor in c++ doesn't work

http://ideone.com/1ohrsO
The push_back called inside the constructor of static_constructor, is not reflected. Why?
#include <iostream>
#include <vector>
#include<memory>
#include<string>
using namespace std;
class has_static_constructor
{
public:
friend class static_constructor;
static vector<int> v;
class static_constructor
{
public:
vector<int> * upt; //&v;
static_constructor()
{
cout<<"inside static_constructor";
upt = &has_static_constructor::v;
has_static_constructor::v.push_back(1);
has_static_constructor::v.push_back(20);
}
} ;
static std::unique_ptr<has_static_constructor::static_constructor> upt ;
};
unique_ptr<has_static_constructor::static_constructor> has_static_constructor::upt(new has_static_constructor::static_constructor());
vector< int > has_static_constructor::v(2,100);
int main() {
// your code goes here
for (std::vector<int>::const_iterator i = has_static_constructor::v.begin(); i != has_static_constructor::v.end(); ++i)
{ std::cout << *i << ' ';
cout<<"\n I was here\n";
}
return 0;
}
Output:
inside static_constructor100
I was here
100
I was here
static_constructor() is called before has_static_constructor::v initialization.
Move
unique_ptr<has_static_constructor::static_constructor> has_static_constructor::upt(new has_static_constructor::static_constructor());
after
vector< int > has_static_constructor::v(2,100);
to have expected behaviour.
But better avoid those global entirely.
You might want to have a look at this way of ordering the code. It removes all initialisation-order dependencies, and in my view neatly separates the public interface from the internal implementation of the static data.
#include <iostream>
#include <vector>
class has_static_constructor
{
// note - all private
struct static_data {
static_data()
: _v(2, 100)
{
_v.push_back(1);
_v.push_back(20);
}
std::vector<int> _v;
};
static static_data& statics() {
static static_data sd;
return sd;
}
// public interface
public:
static std::vector<int>& v() { return statics()._v; }
};
auto main() -> int
{
for (const auto& i : has_static_constructor::v())
{
std::cout << i << std::endl;
}
return 0;
}
expected output:
100
100
1
20

How to get and set a class field in CORBA? (dealing with sequences of CORBA objects)

I have sth like this:
User.idl:
#ifndef __USER_IDL__
#define __USER_IDL__
interface Group;
interface User
{
typedef sequence<Group> Groups;
Groups getGroups();
void setGroups(in Groups g);
};
#endif
UserImpl.h and UserImpl.cpp:
class UserImpl : public POA_User
{
private :
User::Groups groups;
public :
User::Groups* getGroups();
void setGroups(const ::User::Groups& g);
};
#endif
#include "UserImpl.h"
User::Groups* UserImpl::getGroups()
{
return &(this->groups);
}
void UserImpl::setGroups(const ::User::Groups& g)
{
this->groups.length(g.length());
for(int i=0; i<g.length(); i++)
{
this->groups[i] = this->groups[i];
}
}
And Group.idl:
#ifndef __GROUP_IDL__
#define __GROUP_IDL__
#include "User.idl"
interface Group
{
typedef sequence<User> Users;
User getFounder();
void setFounder(in User u);
Users getUsers();
void setUsers(in Users u);
};
#endif
GroupImpl.h, GroupImpl.cpp:
class UserImpl;
class GroupImpl : public POA_Group
{
private :
UserImpl *founder;
Group::Users members;
public :
User_ptr getFounder();
void setFounder(::User_ptr u);
Group::Users* getUsers();
void setUsers(const ::Group::Users& u);
};
User_ptr GroupImpl::getFounder()
{
return this->founder->_this();
}
void GroupImpl::setFounder(::User_ptr u)
{
}
Group::Users* GroupImpl::getUsers()
{
}
void GroupImpl::setUsers(const ::Group::Users& u)
{
}
The question I got here: did I do it right? I mean, is everything ok with this code? I still learn how to write in CORBA and sometimes have doubts especially if it comes to sequences...
The second question: how do I properly set group's founder and get and set group's members?
I mean, I would like to do sth like this in my main file:
#include "UserImpl.h"
#include "GroupImpl.h"
#include <omniORB4/CORBA.h>
#include <omniORB4/Naming.hh>
#include <iostream>
using std::cout;
using std::cerr;
int main(int argc, char **argv)
{
UserImpl u;
u.setLogin("yak");
u.setID(123);
cout << u.getLogin() << "\n";
cout << u.getID() << "\n";
cout << u.toString() << "\n";
GroupImpl **g = new GroupImpl*[1];
for(int i=0; i<1; i++)
{
g[i] = new GroupImpl();
}
u.setGroups(g);
return 0;
}
Please, help:) I use omniORB and C++ language
Ok I think I figured out how to write an implementation of getGroups and getUsers:
User::Groups* UserImpl::getGroups()
{
const size_t size = this->groups.size();
User::Groups_var seqOfObjects = new User::Groups(size);
seqOfObjects->length(size);
size_t i = 0;
vector<GroupImpl*>::const_iterator it = groups.begin();
while (it != groups.end())
{
seqOfObjects[i] = Group::_duplicate((*it)->_this());
++it;
++i;
}
return seqOfObjects._retn();
}
Is that right? But I still have problems with setUsers and setGroups implementations.