The following source will not compile using MSVC 12.
IMCThreadMngr.cpp
#include "IMCThreadMngr.h"
CIMCThreadMngr::CIMCThreadMngr() : mService(),
mWork(mService)
{}
CIMCThreadMngr::~CIMCThreadMngr() {};
void CIMCThreadMngr::StopManager()
{
std::cout << "Manager ceasing" << std::endl;
mService.stop();
mServicethread.join();
std::cout << "Manager ceased" << std::endl;
}
void CIMCThreadMngr::StartManager()
{
mServicethread = boost::thread(boost::bind(&boost::asio::io_service::run, &mService));
}
void CIMCThreadMngr::RegisterThread(const std::string& name, int timeout)
{
if (name.length() == 0) {
std::cout << "No thread name provided" << std::endl;
return;
}
boost::mutex::scoped_lock lock(mGroupMutex);
ThreadObject ob = ThreadObject(mService);
ob.name_ = name;
if (timeout > 0) {
ob.timeout_ = timeout;
}
else {
ob.timeout_ = 2000;
}
mThreadGroup.push_back(ob);
}
void CIMCThreadMngr::UnRegisterThread(const std::string& name)
{
if (name.length() == 0) {
std::cout << "No thread name provided" << std::endl;
return;
}
boost::mutex::scoped_lock lock(mGroupMutex);
std::vector<ThreadObject>::iterator obref;
if (FindThreadObject(name, obref)){
mThreadGroup.erase(obref);
}
}
void CIMCThreadMngr::ThreadCheckIn(const std::string& name){
if (name.length() == 0) {
std::cout << "No thread name provided" << std::endl;
return;
}
boost::mutex::scoped_lock lock(mGroupMutex);
std::vector<ThreadObject>::iterator obref;
if (FindThreadObject(name, obref)){
obref->timer_.cancel();
obref->timer_.expires_from_now(boost::posix_time::seconds(obref->timeout_));
obref->timer_.async_wait(boost::bind(&CIMCThreadMngr::TimeoutElapsed, this));
}
}
bool CIMCThreadMngr::FindThreadObject(const std::string name, std::vector<ThreadObject>::iterator& ob){
for (ob = mThreadGroup.begin(); ob != mThreadGroup.end(); ob++) {
if ((ob->name_.compare(name) == 0)) {
return true;
}
}
return false;
}
void CIMCThreadMngr::TimeoutElapsed(const boost::system::error_code& e, const std::string& name){
boost::mutex::scoped_lock lock(mGroupMutex);
if (e != boost::asio::error::operation_aborted)
{
std::cout << "Thread " << name << " did has not responded" << std::endl; // Timer was not cancelled, take necessary action.
ThreadCheckIn(name);
}
}
IMCThreadMngr.h
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/mutex.hpp>
#include <vector>
class CIMCThreadMngr {
public:
struct ThreadObject {
std::string name_;
int timeout_;
bool threadrunning_;
boost::posix_time::ptime lastupdate_;
boost::asio::deadline_timer timer_;
ThreadObject(boost::asio::io_service& service) : timer_(service)
{
timer_.expires_from_now(boost::posix_time::millisec(3000));
}
};
public:
CIMCThreadMngr();
~CIMCThreadMngr();
void StopManager();
void StartManager();
void RegisterThread(const std::string& name, int timeout);
void UnRegisterThread(const std::string& name);
void ThreadCheckIn(const std::string& name);
bool FindThreadObject(const std::string name, std::vector<ThreadObject>::iterator& ob);
void TimeoutElapsed(const boost::system::error_code& e, const std::string& name);
void TimeoutElapsed( );
private:
boost::asio::io_service mService;
boost::asio::io_service::work mWork;
boost::thread mServicethread;
std::vector<ThreadObject> mThreadGroup;
boost::mutex mGroupMutex;
};
The compiler issue I am running into is as follows
f:\boost\boost_1_57_0\boost\asio\basic_deadline_timer.hpp(510): error C2248: 'boost::asio::basic_io_object<TimerService,false>::operator =' : cannot access private member declared in class 'boost::asio::basic_io_object<TimerService,false>'
with
[
TimerService=boost::asio::deadline_timer_service<boost::posix_time::ptime,boost::asio::time_traits<boost::posix_time::ptime>>
]
f:\boost\boost_1_57_0\boost\asio\basic_io_object.hpp(164) : see declaration of 'boost::asio::basic_io_object<TimerService,false>::operator ='
with
[
TimerService=boost::asio::deadline_timer_service<boost::posix_time::ptime,boost::asio::time_traits<boost::posix_time::ptime>>
]
This diagnostic occurred in the compiler generated function 'boost::asio::basic_deadline_timer<boost::posix_time::ptime,boost::asio::time_traits<boost::posix_time::ptime>,boost::asio::deadline_timer_service<Time,TimeTraits>> &boost::asio::basic_deadline_timer<Time,TimeTraits,boost::asio::deadline_timer_service<Time,TimeTraits>>::operator =(const boost::asio::basic_deadline_timer<Time,TimeTraits,boost::asio::deadline_timer_service<Time,TimeTraits>> &)'
with
[
Time=boost::posix_time::ptime, TimeTraits=boost::asio::time_traits<boost::posix_time::ptime>
]
Hopefully the issue is something fairly straight forward, though I can't find an obvious difference between my code above, and the boost examples of deadline_timer.
boost::asio::deadline_timer is neither copyable nor moveable (nor copy-assignable nor move-assignable). As a result, neither is CIMCThreadMgr::ThreadObject, which means that you cannot have a std::vector<ThreadObject>.
A simple way around this problem is to hold the deadline_timer in a shared_ptr, as in
struct ThreadObject {
std::string name_;
int timeout_;
bool threadrunning_;
boost::posix_time::ptime lastupdate_;
// HERE
std::shared_ptr<boost::asio::deadline_timer> timer_;
ThreadObject(boost::asio::io_service& service)
// Also HERE
: timer_(std::make_shared<boost::asio::deadline_timer>(service))
{
// -> instead of . now.
timer_->expires_from_now(boost::posix_time::millisec(3000));
}
};
If you go this route, you'll also have to replace . with -> where timer_ is being used:
if (FindThreadObject(name, obref)){
// vv-- HERE
obref->timer_->cancel();
obref->timer_->expires_from_now(boost::posix_time::seconds(obref->timeout_));
obref->timer_->async_wait(boost::bind(&CIMCThreadMngr::TimeoutElapsed, this));
}
It is probably possible to use a std::unique_ptr, but that may require larger changes to your code than replacing . with -> in a few places (because ThreadObject would only be moveable but not copyable).
Related
here is my code, when i try running this, main does output the information placed into the LoggerComponent, but not the Logger itself. I don't know why, what could be preventing the logger from passing information into the underlying loggercomponent?
i tried using information from http://www.cplusplus.com/reference/map/map/
and from https://www.geeksforgeeks.org/map-associative-containers-the-c-standard-template-library-stl/
logger.cpp:
#include "logger.hpp"
Logger::Logger(bool verbose, bool fileoutput)
{
if(verbose)
{
LoggerComponent c1(LoggerLevel::DEBUG, &std::cout);
addLogger (LoggerType::CONSOLE, &c1);
c1.output (LoggerLevel::DEBUG, "This is the start of console output");
}
if(fileoutput)
{
}
}
void Logger::output(LoggerLevel level, std::string message)
{
for(auto& x : components)
{
x.second->output (level, message);
}
}
void Logger::addLogger(LoggerType type, LoggerComponent* component)
{
if(components.find (type) == components.end ())
components.emplace(type, component);
}
LoggerComponent* Logger::getLogger (LoggerType type)
{
if(components.find (type) != components.end ())
return components.at (type);
return nullptr;
}
void Logger::clearLoggers()
{
components.clear ();
}
void Logger::removeLogger(LoggerType type)
{
if(components.find (type) != components.end ())
components.erase (type);
}
logger.hpp
#ifndef LOGGER_HPP
#define LOGGER_HPP
#include "loggercomponent.hpp"
#include <map>
enum class LoggerType
{
CONSOLE,
FILE
};
class Logger
{
public:
explicit Logger(bool verbose, bool fileoutput);
void output(LoggerLevel level, std::string message);
void addLogger(LoggerType type, LoggerComponent* component);
void removeLogger(LoggerType type);
void clearLoggers();
LoggerComponent* getLogger(LoggerType type);
private:
std::map<LoggerType, LoggerComponent*> components;
};
#endif // LOGGER_HPP
main.cpp
#include "logger.hpp"
int main()
{
int* p;
int i = 5;
int j = 5;
p = &i;
std::cout << p << std::endl;
p = &j;
std::cout << p << std::endl;
LoggerComponent c(LoggerLevel::DEBUG, &std::cout);
c.output (LoggerLevel::INFO, "Hello World!");
c.output (LoggerLevel::CRITICAL, "Hello World!");
Logger c2(true, true);
std::cout << c.getOutputStream () << std::endl;
std::cout << c2.getLogger (LoggerType::CONSOLE)->getOutputStream () << std::endl;
c2.output (LoggerLevel::INFO, "Hello World!");
c2.output (LoggerLevel::CRITICAL, "Hello World!");
}
loggercomponent.hpp
#ifndef LOGGERCOMPONENT_HPP
#define LOGGERCOMPONENT_HPP
#include <iostream>
#include <string>
#include <ctime>
enum class LoggerLevel
{
INFO,
DEBUG,
WARNING,
ERROR,
CRITICAL
};
class LoggerComponent
{
public:
explicit LoggerComponent(LoggerLevel level, std::ostream* output);
LoggerLevel getMinimumLevel();
std::ostream* getOutputStream();
void setMinimumLevel(LoggerLevel level);
void setOutputStream(std::ostream* output);
void output(LoggerLevel level, std::string outputMessage);
private:
std::string getLevelString(LoggerLevel level);
LoggerLevel minimumLevel;
std::ostream* outputStream;
};
#endif // LOGGERCOMPONENT_HPP
loggercomponent.cpp
#include "loggercomponent.hpp"
LoggerComponent::LoggerComponent(LoggerLevel level,
std::ostream* output)
{
setMinimumLevel (level);
setOutputStream (output);
}
void LoggerComponent::setMinimumLevel(LoggerLevel level)
{
if(minimumLevel != level)
minimumLevel = level;
}
void LoggerComponent::setOutputStream(std::ostream *output)
{
if(outputStream != output)
outputStream = output;
}
LoggerLevel LoggerComponent::getMinimumLevel()
{
return minimumLevel;
}
std::ostream* LoggerComponent::getOutputStream()
{
return outputStream;
}
std::string LoggerComponent::getLevelString(LoggerLevel level)
{
switch (level) {
case LoggerLevel::INFO:
return "INFO";
case LoggerLevel::DEBUG:
return "DEBUG";
case LoggerLevel::WARNING:
return "WARNING";
case LoggerLevel::ERROR:
return "ERROR";
case LoggerLevel::CRITICAL:
return "CRITICAL";
}
return nullptr;
}
void LoggerComponent::output(LoggerLevel level, std::string outputMessage)
{
if(level >= minimumLevel)
{
time_t now = time(nullptr);
*outputStream << ctime(&now)
<< (getLevelString (level) + " >> " + outputMessage)
<< std::endl << std::endl;
}
}
output:
0x60fda8
0x60fdac
Tue Oct 01 12:29:14 2019
CRITICAL >> Hello World!
Tue Oct 01 12:29:14 2019
DEBUG >> This is the start of console output
0x6fd0cd00
0x60fdb0
You are storing a pointer to an object local to the constructor (c1) in components. It will be destroyed and the pointer invalid when you try to use it later.
Store the object itself (or a std::unique_ptr to it if you have a good reason not to store the object itself) in the map instead.
I am trying to implement observer design pattern in C++ as below
#include <iostream>
#include <vector>
using namespace std;
class observer
{
public:
observer() = default;
~observer() = default;
virtual void notify() = 0;
};
class subject
{
vector <observer *> vec;
public:
subject() = default;
~subject() = default;
void _register(observer *obj)
{
vec.push_back(obj);
}
void unregister(observer *obj)
{
int i;
for(i = 0; i < vec.size(); i++)
{
if(vec[i] == obj)
{
cout << "found elem. unregistering" << endl;
vec.erase(vec.begin() + i);
break;
}
}
if(i == vec.size())
{
cout << "elem not found to unregister" << endl;
}
}
void notify()
{
vector <observer *>::iterator it = vec.begin();
while(it != vec.end())
{
(*it)->notify();
it ++;
}
}
};
class obsone : public observer
{
void notify()
{
cout << "in obsone notify" << endl;
}
};
class obstwo : public observer
{
void notify()
{
cout << "in obstwo notify" << endl;
}
};
int main()
{
subject sub;
obsone *one = new obsone();
obstwo *two = new obstwo();
sub._register(one);
sub._register(two);
sub.notify();
sub.unregister(one);
sub.notify();
//delete two;
//sub.notify();
return 0;
}
I am registering the objects with the subject explicitly. Is it the correct way of doing it or do I need to register through observer class only. Are there any problems with the above approach?
Here's an example of doing the callbacks with lambdas and function objects in the callback collection.
The details can vary greatly! So, this code is not “the” way, but just your code rewritten in one specific way, out of a myriad possibilities. But it hopefully shows the general idea in modern C++.
#include <iostream>
#include <functional> // std::function
#include <stdint.h> // uint64_t
#include <unordered_map> // std::unordered_map
#include <utility> // std::move
#include <vector> // std::vector
using namespace std;
namespace my
{
using Callback = function<void()>;
template< class Key, class Value > using Map_ = unordered_map<Key, Value>;
class Subject
{
public:
enum Id: uint64_t {};
private:
Map_<uint64_t, Callback> m_callbacks;
static auto id_value()
-> uint64_t&
{
static uint64_t the_id;
return the_id;
}
public:
auto add_listener( Callback cb )
-> Id
{
const auto id = Id( ++id_value() );
m_callbacks.emplace( id, move( cb ) );
return id;
}
auto remove_listener( const Id id )
-> bool
{
const auto it = m_callbacks.find( id );
if( it == m_callbacks.end() )
{
return false;
}
m_callbacks.erase( it );
return true;
}
void notify_all() const
{
for( const auto& pair : m_callbacks )
{
pair.second();
}
}
};
}
struct Observer_1
{
void notify() { cout << "Observer_1::notify() called." << endl; }
};
struct Observer_2
{
void notify() { cout << "Observer_2::notify() called." << endl; }
};
auto main()
-> int
{
my::Subject subject;
Observer_1 one;
Observer_2 two;
using Id = my::Subject::Id;
const Id listener_id_1 = subject.add_listener( [&]{ one.notify(); } );
const Id listener_id_2 = subject.add_listener( [&]{ two.notify(); } );
cout << "After adding two listeners:" << endl;
subject.notify_all();
cout << endl;
subject.remove_listener( listener_id_1 )
and (cout << "Removed listener 1." << endl)
or (cout << "Did not find registration of listener 1." << endl);
cout << endl;
cout << "After removing or attempting to remove listener 1:" << endl;
subject.notify_all();
}
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.
struct taskinfo
{
long int id;
bool cancel;
std::function<void()> func;
std::chrono::system_clock::time_point time;
std::chrono::system_clock::duration interval;
taskinfo(){ }
bool operator<(const taskinfo& task) const {
return time > task.time;
}
public:
taskinfo(long int id, std::function<void()>&& f, const std::chrono::system_clock::time_point& t)
: id(id), func(f),
time(t)
{
cancel = false;
}
}
....
std::priority_queue<taskinfo, std::vector<taskinfo>> tasks;
void at(taskinfo** task){
std::function<void()> threadFunc = [task]() { std::thread((*task)->func).detach(); };
(*task)->func = threadFunc;
tasks.push(**task);
}
In main()..
std::vector<taskinfo*> requests;
for(int i=1; i <=5; i++ )
{
taskinfo* t = new taskinfo(i, [i]{ timeoutFunc(i); }, std::chrono::system_clock::now() + std::chrono::milliseconds(timeout));
tT.at(&t);
requests.push_back(t);
std::cout << "Request " << i << " Registered.... Time:" << std::chrono::system_clock::now().time_since_epoch().count() << std::endl;
}
I think I am missing something here when I pop the function out of the queue to execute, the function may be empty, Nothing is getting executed.
If i copy taskinfo to locally
void at(taskinfo** task){
taskinfo t = **task;
//Replace everything else with t function works fine But
//I need to modify the same reference
}
How can I work with pointer reference herein lambda?
I have added the complete code of what i am trying to do here.
Complete Code:
#include <functional>
#include <chrono>
#include <future>
#include <queue>
#include <thread>
#include <memory>
#include <sstream>
#include <assert.h>
#include <iostream>
#include <ctime>
#include <sys/time.h>
#include <unistd.h>
#include <limits.h>
#define TIMER_NO_TASK_SLEEP_TIME 100
struct taskinfo
{
long int id;
bool cancel;
std::function<void()> func;
std::chrono::system_clock::time_point time;
std::chrono::system_clock::duration interval;
taskinfo(){ }
bool operator<(const taskinfo& task) const {
return time > task.time;
}
public:
taskinfo(long int id, std::function<void()>&& f, const std::chrono::system_clock::time_point& t)
: id(id), func(f),
time(t)
{
cancel = false;
}
};
class TimerTask
{
private:
std::priority_queue<taskinfo, std::vector<taskinfo>> tasks;
std::unique_ptr<std::thread> thread;
bool keepRunning;
public:
TimerTask()
:keepRunning(true),
thread(new std::thread([this]() {
while(keepRunning)
{
auto now = std::chrono::system_clock::now();
while(!tasks.empty() && tasks.top().time <= now) {
if(!tasks.top().cancel)
{
tasks.top().func();
}
tasks.pop();
}
if(tasks.empty()) {
std::this_thread::sleep_for(std::chrono::milliseconds(TIMER_NO_TASK_SLEEP_TIME));
} else {
std::this_thread::sleep_for(tasks.top().time - std::chrono::system_clock::now());
}
}
})){ }
~TimerTask()
{
keepRunning = false;
thread->join();
}
//Execute a task when the timer times out
void at(taskinfo** task){
std::function<void()> threadFunc = [task]() { std::thread((*task)->func).detach(); };
(*task)->func = threadFunc;
tasks.push(**task);
}
//Cancel the particular task with a flag
void cancel(taskinfo** task){
(* task)->cancel = true;
}
};
//The return type of the task must be void
void timeoutFunc(int id)
{
std::cout << "Request " << id << " Timeout.... Executed Timeout Function Time:" << std::chrono::system_clock::now().time_since_epoch().count() << std::endl;
}
int main(int argc, char* argv[])
{
if(argc != 2)
{
std::cout << "\n Usage <Process> <Timeout>" << std::endl;
return 0;
}
int timeout = atoi(argv[1]);
TimerTask tT;
std::vector<taskinfo*> requests;
requests.reserve(1000);
for(int i=1; i <=5; i++ )
{
taskinfo* t = new taskinfo(i, [i]{ timeoutFunc(i); }, std::chrono::system_clock::now() + std::chrono::milliseconds(timeout));
tT.at(&t);
requests.push_back(t);
std::cout << "Request " << i << " Registered.... Time:" << std::chrono::system_clock::now().time_since_epoch().count() << std::endl;
}
while(1) sleep(60);
return 0;
}
You are passing a pointer to a pointer which no longer exists:
taskinfo* t = new taskinfo(i, [i]{ timeoutFunc(i); }, std::chrono::system_clock::now() + std::chrono::milliseconds(timeout));
tT.at(&t);
requests.push_back(t);
In the above code t is a local variable instantiated for each iteration through the loop. You get a new t every time.
The code tT.at(&t); gets the address of this temporary.
The fix is at the calling site call: tT.at(t);. notice how this is just like requests.push_back(t);
Also:
//Execute a task when the timer times out
void TimerTask::at(taskinfo* task){
std::function<void()> threadFunc = [task]() { std::thread(task->func).detach(); };
task->func = threadFunc;
...
}
The subject (I mean overloading operators, default and copy constructors etc.) is something new for me and I really don't get it. I tried to avoid it but it has got me anyway. I have a container std::vector<Employee> with objects. Even thought I don't use = operator
I get the error:
C2280 'Employee &Employee::operator =(const Employee &)': attempting to reference a deleted function.
The error stops occur if I remove the line employees.erase(employees.begin() + 1);
I've found out that is a common problem but still I can't find any solution. Please take a look at the code:
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
class Employee
{
public:
std::string name, profession;
std::string current_task = "NONE";
int id, age, warrings;
std::vector<std::string>& tasks;
Employee::Employee(std::vector<std::string>& tasks) : tasks(tasks)
{
warrings = 0;
};
virtual void AssignNewTask(std::string input_string)
{
for (unsigned int i = 0; i < tasks.size(); i++)
{
if (input_string == tasks[i])
{
current_task = input_string;
std::cout << ">> Przydzielony nowy task!" << std::endl;
return;
}
}
std::cout << input_string << "nie nalezy do listy obowiazkow " << profession << std::endl;
}
};
class HR : public Employee
{
private:
static std::vector<std::string> tasks;
public:
HR::HR() : Employee(tasks)
{
Employee::profession = "HR Specialist";
}
};
class Helpdesk : public Employee
{
private:
static std::vector<std::string> tasks;
public:
Helpdesk::Helpdesk() : Employee(tasks)
{
Employee::profession = "Helpdesk Technician";
}
};
std::vector<std::string> HR::tasks = { "HR task" };
std::vector<std::string> Helpdesk::tasks = { "Helpdesk task" };
bool operator==(const Employee & obj, const std::string & std)
{
if ((obj.name == std) || (std == obj.name))
{
return true;
}
else
{
return false;
}
}
int main()
{
std::vector<Employee> employees;
std::cout << "Welcome message" << std::endl;
// it works
employees.push_back(HR());
employees.push_back(Helpdesk());
// it also works
employees.pop_back();
employees.push_back(Helpdesk());
// the issue occurs !
employees.erase(employees.begin() + 1);
system("pause");
}
I guess that I should overload a = operator but I even don't know how to begin. I've marked where the issue occurs.
The problem is here:
class Employee
{
public:
std::string name, profession;
std::string current_task = "NONE";
int id, age, warrings;
std::vector<std::string> *tasks; // <=== use a pointer
Employee(std::vector<std::string>& tasks) : tasks(&tasks)
{
warrings = 0;
};
You can't define a operator= since you can't assign a reference (tasks). Remove the reference and it will be all OK (maybe slower, but safer)