Hello I'm new here and new to C++. I have a problem where I need to make backup copy of my vector of pointers. But I can't relly get it properly. I found solution to my case on this forum but can't relly get it right:
class cloneFunctor {
public:
T* operator() (T* a) {
return a->clone();
}
}
I tried to implement this into my code but could't get a good resolve, could anyone help me to get this thing right?
My code:
sever.cpp
#include "server.h"
#include <iostream>
#include <functional>
#include <algorithm>
#include <iterator>
class Client;
class cloneFunctor {
public:
cloneFunctor* operator() (cloneFunctor* a) {
return a->clone();
}
};
Server *Server::instance = 0;
Server& Server::getInstance() {
if (instance == 0)
instance = new Server();
return (*instance);
}
void Server::setStatus(bool status) {
this->nStatus = status;
changeClientStatus();
writeStateToConsole();
}
bool Server::getStatus() {
return nStatus;
}
void Server::writeStateToConsole() {
std::cout << "Server state: " << getStatus() << std::endl;
}
void Server::subscribeToServer(Client &temp) {
listOfClients.push_back(&temp);
}
void Server::writeClients() {
for (unsigned int i = 0; i < listOfClients.size(); i++) {
std::cout << i+1 << ". client status: " << listOfClients[i]->getStatus() << std::endl;
}
}
void Server::changeClientStatus() {
if (nStatus == 0){
makeCopy(listOfClients);
for (unsigned int i = 0; i < listOfClients.size(); i++) {
listOfClients[i]->setStatus(false);
}
}
else
restoreCopy();
}
void Server::makeCopy(std::vector<Client *>listOfClients) {
transform(listOfClients.begin(), listOfClients.end(), back_inserter(listOfClientsOld), cloneFunctor());
}
void Server::restoreCopy() {
}
server.h
#ifndef SERVER_H_
#define SERVER_H_
#include "abstractbaseclass.h"
#include "server.h"
#include "client.h"
class Client;
class Server : public Abstractbaseclass {
friend class Client;
public:
static Server& getInstance();
virtual void setStatus(bool status);
virtual bool getStatus();
virtual void writeStateToConsole();
void subscribeToServer(Client &temp);
void writeClients();
void changeClientStatus();
void makeCopy(std::vector<Client *>listOfClients);
void restoreCopy();
private:
static Server *instance;
Server(){};
std::vector <Client *>listOfClients;
std:: vector <Client *> listOfClientsOld;
};
#endif /* SERVER_H_ */
Program should create singleton Server class, and then create 3 clients who will subsribe to server (these are hold in vector of pointers). When I set server status to 0, all clients change their state to off (bool false) and befeore this should be created backup vector, becouse when I'll turn on server again clients need to switch to their state from before shutting down server.
OK, so he's trying to teach some sort of transaction-based thinking.
Client may need an assignment operator
Client & operator=(Client & toCopy)
{
// copy all of toCopy's members over to this
}
if it doesn't already have one and contains pointers or complex data types that you can't trust to self-copy.
Now you can easily
clientA = clientB;
to copy clientB into clientA
Then we get to the main event, Server::restoreCopy(), and it's a brutally simple variant of:
if (listOfClients.size() != listOfClientsOld.size())
{
// back up is stale. Probably throw exception
}
for (size_t index = 0; index < listOfClients.size(); index++)
{
*listOfClients[index] = *listOfClientsOld[index];
}
These are vectors of pointers so you must dereference (*) the pointer to get the pointed at Client or you copy the pointer and not the pointed at. Remember that clone of Client is a totally different Clientand not what Server's user passed in in the first place. If the Server user is still holding onto the initial Client and using it, bad ju-ju will happen if you only copy the pointers. Both sides will be operating on different Clients even though they may look the same. So much as one modification and they won't
You can also use the std::transform trick used to make the back-up here as well, but this is simple and obvious and easy to debug. Feel free to use iterators and range-based for as well.
And while you are at it, pray no one has reordered listOfClients since you made the back-up.
Important side notes:
void makeCopy(std::vector<Client *>listOfClients);
is weird. It allows a Server user to pass in their own vector and add to any existing back-ups. This includes Server itself. It does not remove any existing back up, so listOfClientsOld will keep growing. And because anyone who has access to the Server can call it and pass in their own vector, they can stuff that back up full of fallacious nonsense. I'd recommend that makeCopy take no parameters and remove any existing Clients from the backup, and delete them. Better still, listOfClientsOld has no need to store pointers at all and probably shouldn't.
Lots of pointers in play and no deletes. Somebody has to give back all of that memory you're allocating or you'll eventually run out.
Related
I'm creating a program that will simulate a race between various runners, using behavior classes to implement different types of runner movements.
To do this, an abstract MoveBehaviour class will be implemented, along with several other concrete sub-classes (etc. WalkBehaviour, SleepBehaviour, SlideBehaviour).
The abstract MoveBehaviour class will require a pure virtual move() function, and the appropriate behaviour will be implemented in the concrete sub-classes. This move() function computes a new position newPos for the runner, given its current position oldPos, and the move() function will return a short, text description of the move in the log parameter (Etc. "walk forward 1 step") , which will be printed to the screen in a later step. I feel as if I'm not returning my log values in these functions correctly, and this relates to another issue.
In the update() function in Runner.cc, I'm supposed to randomly select the runner’s next move behaviour. This involves a new walking behaviour 40% of the time, a sleeping behaviour 40% of the time, and a slide behaviour 20% of the time. I'm supposed to use the new behaviour object to compute a new position that will be stored in the newPos parameter, and then I am to document the move in the runner’s current log data member. Etc if the runner is named Timmy, and the new move behaviour is walking, the current log data member will store the string “Timmy walked one step.”
Going back to my log, I wasn't sure how I would access the string that I declared in each of the move functions for every behaviour class. I noticed there is a getLog() function in Runner.cc, but I feel like it doesn't make sense to use that. This makes me thing I wasn't supposed to declare the "walked one step" strings and such in the move classes but rather in the update classes instead.
Additionally, I don't understand how to get the new behaviour object to compute a new position that will be stored in the newPos parameter and would appreciate some help with that as well.
For getting the log values, I'm just printing the runner's name below and my attempt was going to append whatever was in the log value to this sentence, but I wasn't sure how to access the log values.
I can include the SleepBehaviour and SlideBehaviour classes if needed, but they are practically identical to WalkBehaviour and I figured only one example was needed.
Runner.cc
void Runner::update(Position& newPos){
int r;
r = random(100) + 1;
if(r <= 40){
WalkBehaviour* walk = new WalkBehaviour;
}else if (r <= 40){
SleepBehaviour sleep = new SleepBehaviour;
}else{
SlideBehaviour* slide = new SlideBehaviour;
}
cout << name << endl;
}
Position.cc
#include <iostream>
using namespace std;
#include <string>
#include "Position.h"
Position::Position(int i1, int i2) : row(i1), column(i2){
}
Position::getRow(){ return row; }
Position::getColumn(){ return column; }
void Position::setRow(int r){ row = r; }
void Position::setColumn(int c){ column = c; }
MoveBehaviour.h
#ifndef MOVEBEHAVIOUR_H
#define MOVEBEHAVIOUR_H
#include <iostream>
#include "Position.h"
using namespace std;
class MoveBehaviour
{
public:
virtual void move(Position&, Position&, string&) = 0;
virtual ~MoveBehaviour() = default;
};
class WalkBehaviour : public MoveBehaviour{
public:
virtual void move(Position&, Position&, string&);
virtual ~WalkBehaviour();
};
class SleepBehaviour : public MoveBehaviour{
public:
virtual void move(Position&, Position&, string&);
virtual ~SleepBehaviour();
};
class SlideBehaviour : public MoveBehaviour{
public:
virtual void move(Position&, Position&, string&);
virtual ~SlideBehaviour();
};
WalkBehaviour.cc
#include <iostream>
using namespace std;
#include <string>
#include "MoveBehaviour.h"
void WalkBehaviour::move(Position& oldPos, Position& newPos, string& log) {
newPos.setColumn(oldPos.getColumn() + 1);
newPos.setRow(oldPos.getRow());
log = (" walked one step \n");
}
WalkBehaviour::~WalkBehaviour(){}
First, you need to actually use polymorphism by declaring a pointer to a base MoveBehaviour object that you let point to a derived instance.
Additionally, you need to make sure that you don't leak memory, so I chose std::unique_ptr which is automatically freed upon function exit.
Next, you can simply pass an empty std::string for the function to assign the log to, and use a std::stringstream to construct a line with the name with the move description. The output of this stringstream is then added to the log member in one go.
void Runner::update(Position& newPos) {
int r;
r = random(100) + 1;
std::unique_ptr<MoveBehaviour> movement;
if(r <= 40) {
movement = make_unique<WalkBehaviour>();
} else if (r <= 80) {
movement = make_unique<SleepBehaviour>();
} else {
movement = make_unique<SlideBehaviour>();
}
std::string moveLog;
movement->move(currPos, newPos, moveLog);
currPos = newPos;
std::stringstream ss;
ss << name << " " << moveLog << std::endl;
log += ss.str();
}
Here:
if(r <= 40){
WalkBehaviour* walk = new WalkBehaviour;
}else if (r <= 40){
SleepBehaviour sleep = new SleepBehaviour;
}else{
SlideBehaviour* slide = new SlideBehaviour;
}
you are creating new behaviors and immediately leaking them. You should have assign them ti Runner's MoveBehaviour* behaviour;, deleting its old behavior first:
delete behaviour;
if(r <= 40){
behaviour = new WalkBehaviour;
}else if (r <= 40){
behaviour = new SleepBehaviour;
}else{
behaviour = new SlideBehaviour;
}
Your WalkBehaviour::move() uses log correctly (except that you don't need to enclose text literal into ()
I just started to work with Wt, and it seems that memory used by
the program is constantly increasing (as shown by System Monitor on Ubuntu).
This happens in many different contexts, event though the destructors are invoked.
My guess is that Wt is keeping copies of some data, and I wonder if there is a way to
force Wt to free that memory.
The simplest example (appended below) is an app that
creates/deletes a WText with a huge string. Calling create/delete slots multiple times
causes a constant memory increase. For fun, I added two buttons that call those slots from the browser.
Here is the code
#include <Wt/WApplication.h>
#include <Wt/WBreak.h>
#include <Wt/WContainerWidget.h>
#include <Wt/WPushButton.h>
#include <Wt/WText.h>
using namespace Wt;
class App: public Wt::WApplication
{
public:
App(const Wt::WEnvironment& env);
private:
static std::string createHugeString();
void createWText()
{ if(!m_widgetPtr)
m_widgetPtr=this->root()->addNew<Wt::WText>(createHugeString());
}
void deleteWText()
{ if(m_widgetPtr)
auto uptr=root()->removeChild(m_widgetPtr);
// will be deleted by unique_ptr dtor
m_widgetPtr=nullptr;
}
Wt::WWidget *m_widgetPtr = nullptr;
};
App::App(const Wt::WEnvironment& env)
:Wt::WApplication(env)
{
auto *createTextButtonPtr = root()->addNew<WPushButton>("Create WText");
auto *delTextButtonPtr = root()->addNew<WPushButton>("Delete WText");
root()->addNew<WBreak>();
createTextButtonPtr->clicked().connect(this,&App::createWText);
delTextButtonPtr->clicked().connect(this,&App::deleteWText);
} //constructor
std::string App::createHugeString()
{
std::string htmlStr;
for(std::size_t i =0; i!=20000000/4; ++i){
htmlStr += "a b ";
}
return htmlStr;
}
int main()
{
char* argv[]= {"progname", "--docroot", "." ,
"--http-address", "0.0.0.0",
"--http-port", "8080"
};
int argc = sizeof(argv)/sizeof(*argv);
return Wt::WRun(argc, argv, [](const Wt::WEnvironment& env) {
return std::make_unique<App>(env);
});
}
createHugeString() would probably increase memory usage, even without leak: you fragment the memory.
reserve correct dimension for htmlStr should avoid some fragmentations.
I am building a console application in wich I am only using smart pointers. I made the choice to only use smart pointers to learn when to use which smart pointer. In this application, I am trying to use a state pattern to switch between the different states. The base class is TurnState from this class all the other state-classes inherit.
In the gamecontroller, I have defined the current state. For switching between the states I want to use an unordered_map with an enum as key and the state class as value. But as soon as I wrote down std::unordered_map<TurnStateEnum, std::shared_ptr<TurnState>> _turn_states_map; inside the header I got some memory leaks.
To get rid of those memory leaks I tried to destroy them in the deconstructor like this:
GameController::~GameController()
{
for (std::unordered_map<TurnStateEnum, std::shared_ptr<TurnState>>::iterator iterator{ _turn_states_map.begin() }; iterator != _turn_states_map.end(); iterator++) {
iterator->second.reset();
_turn_states_map.erase(iterator);
}
_turn_states_map.clear();
}
But that did not work out either. I was able to solve it using raw pointers but that is not what I am trying to achieve. So my question is, how do I delete a map with shared_ptrs in the correct way?
All help will be appreciated.
Edit 1 - Minimal example
The Game Controller will be used for holding a shared_ptr to the current state and switching to the next one.
Below is the GameController header:
class GameController
{
public:
GameController();
~GameController();
void do_action(Socket& client, Player& player, std::string command);
void set_next_state(TurnStateEnum state);
private:
std::unordered_map<TurnStateEnum, std::shared_ptr<TurnState>> _turn_states_map;
std::shared_ptr<TurnState> _turn_state;
void initialize_turn_states_map();
};
Below is the GameController source:
GameController::GameController()
{
initialize_turn_states_map();
_turn_state = _turn_states_map.at(TurnStateEnum::SETUP);
}
GameController::~GameController()
{
for (std::unordered_map<TurnStateEnum, std::shared_ptr<TurnState>>::iterator iterator{ _turn_states_map.begin() }; iterator != _turn_states_map.end(); iterator++) {
iterator->second.reset();
_turn_states_map.erase(iterator);
}
_turn_states_map.clear();
}
void GameController::do_action(Socket& client, Player& player, std::string command)
{
_turn_state->do_turn(client, player, command);
}
void GameController::set_next_state(TurnStateEnum state)
{
_turn_state = _turn_states_map.at(state);
}
void GameController::initialize_turn_states_map()
{
_turn_states_map.insert(std::make_pair(TurnStateEnum::SETUP, std::make_shared<SetupState>(*this)));
}
The TurnState is the base class. This class should contain the current logic/behaviour of the application.
Below the TurnState header:
class GameController;
class TurnState
{
public:
TurnState(GameController& gameCtrl);
virtual ~TurnState();
void next_state(TurnStateEnum stateEnum);
virtual void do_turn(Socket& client, Player& player, std::string command) = 0;
protected:
GameController& _gameCtrl;
};
Below the TurnState source:
TurnState::TurnState(GameController& gameCtrl) : _gameCtrl ( gameCtrl )
{
}
TurnState::~TurnState()
{
}
void TurnState::next_state(TurnStateEnum stateEnum)
{
_gameCtrl.set_next_state(stateEnum);
}
Setup State does not have any other variables or methods than his base class and for now, the methods are empty.
Edit 2 - Minimal example v2
This might be a better minimal example. I created a console project and uploaded it to: https://ufile.io/ce79d
There are no leaks in your program. You are using std::shared_ptr correctly. There are no circular references to fix. Although the destructors were redundant, they were harmless.
You are just not using _CrtDumpMemoryLeaks() right. You are calling it before destructors for local objects in main are run. Naturally it will report memory allocated by these objects as leaks.
To fix:
int main(int argc, const char * argv[])
{
(
GameController gameCtrl = GameController();
gameCtrl.do_action("test");
}
_CrtDumpMemoryLeaks();
return 0;
}
I have simplified the code as much as possible.
So I have two class:
class EntityManager
{
public:
std::shared_ptr<std::vector<Entity> > getEntities()
{
return std::make_shared<std::vector<Entity> >(m_entities);
}
private:
std::vector<Entity> m_entities{};
};
and
class System
{
public:
void loadEntities(std::shared_ptr<std::vector<Entity> > entities)
{
m_entities = entities;
}
private:
std::shared_ptr<std::vector<Entity> > m_entities;
};
Now basically I want the m_entities of System to point to the m_entities of EntityManager.
I did this:
system = System();
system.loadEntities(m_entityManager.getEntities());
But then I pushed back an element into the m_entities vector of EntityManager and this element wasn't added in the m_entities vector of System, which means my pointer doesn't point.
Where is my mistake?
Thanks!
Your problem is this line: return std::make_shared<std::vector<Entity> >(m_entities);
What is happening is that the shared_ptr manages a new std::vectory<Entity> container which is initialized as a copy of m_entities. Therefore, modifying the instance in the shared_ptr doesn't modify the data member in the EntityManager class and of course the shared_ptr won't see changes made to EntityManager::m_entities.
std::make_shared doesn't "make this thing shared"; it "makes a thing that will be shared".
So, you can't just make a shared pointer out of nowhere that points to something that already exists.
Your code dynamically allocates a std::vector, copy constructed from m_entities and managed by a std::shared_ptr. It's shorthand for this:
std::vector<Entity>* ptr_to_copy = new std::vector<Entity>(m_entities);
return std::shared_ptr(ptr_to_copy);
It's not clear what you're trying to do, from the code that (by your own admission) does not achieve that goal. But it seems unlikely that std::shared_ptr is appropriate here.
If it is, then make the vector dynamically-allocated and shared from the start; otherwise, just return a reference to the vector as it is.
Hack example of a pointer-free solution.
#include <string>
#include <iostream>
#include <vector>
//Hack-sample Entity class
class Entity
{
public:
Entity(const char * name): m_name(name)
{
}
void print() // this is stupid in real life. Prefer a << overload
{
std::cout << "Hi! I'm " << m_name << "!\n";
}
private:
std::string m_name;
};
class EntityManager
{
private:
std::vector<Entity> m_entities;
public:
// hide the fact that a vector is being used to store the entities.
// you can now swap out the vector for most standard containers without
// changing any code other than the using and the declaration of m_entities
using iterator = std::vector<Entity>::iterator;
EntityManager(): m_entities({"bob", "bill"})
// just pre-loading a few test entities
{
// RAII says you should load the entities from their source here
}
// get the first entity.
iterator begin()
{
return m_entities.begin();
}
// get the end of the entity list
iterator end()
{
return m_entities.end();
}
// adds an entity
void addEntity(const Entity & entity)
{
m_entities.push_back(entity);
}
// removes an entity
iterator removeEntity(iterator rem)
{
return m_entities.erase(rem);
}
};
class System
{
public:
// example method to show System working with EntityManager by printing all of the Entities
void printEntities()
{
for (EntityManager::iterator it = m_entityManager.begin();
it != m_entityManager.end();
++it)
{
it->print();
}
}
// example method to show System working with EntityManager by adding Entities
void addMoreEntities()
{
m_entityManager.addEntity(Entity("Ted \"Theodore\" Logan"));
m_entityManager.addEntity(Entity("Excellent!!!"));
}
private:
EntityManager m_entityManager ;
};
// sample test
int main()
{
System test;
test.printEntities();
test.addMoreEntities();
test.printEntities();
}
THIS HAS BEEN A HACK. THIS HAS ONLY BEEN A HACK.
If you want to do EntityManager right, see Writing your own STL Container for hints. If you want all of the bells and whistles, the job is fairly complicated. Depending on how you are using EntityManager and the complexity of the Entity management logic, you may be better off discarding EntityManager and just using the plain, old std::vector.
Addendum: What is meant by Resource Acquisition is Initialization (RAII)?
I've been working on a server written in C++ and using SFML networking for the sockets and all. However, I've ran into a bit of a dead end for me. SFML Sockets are non-copyable and thus cannot be stored into most(all the ones that I know of) stl containers.
So, I quickly jumped to the idea of using a pointer and then it hit me that I should use RAII, but I hate smart pointers and needed to store more information than just the pointer to the Socket class.
I wrote a Client class that wraps the socket and deletes it when the destructor on the Client class gets called, which is fine and dandy..until I remembered that the stl containers will copy my class, delete the pointer and then I'd be left with a dangling pointer.
So, is there anyway I can get around non-copyables? I need the pointer to be stored within the class and I need the class to destroy the allocated memory.
I figured I could use a copy constructor to set the copied classes' pointer to null, but I cannot find a way to do that.
For Reference:
Client.cpp
Client::Client()
{
};
Client::Client(sf::TcpSocket* in_Connection)
{
m_Connection = in_Connection;
m_IPAddress = m_Connection->getRemoteAddress().toString();
m_AccountName = "NOACCOUNT";
m_CharacterName = "NOCHARACTER";
};
Client::~Client()
{
m_Connection->disconnect();
delete m_Connection;
};
//getters
sf::TcpSocket* Client::getConnection()
{
return m_Connection;
};
std::string Client::getIPAddress()
{
return m_IPAddress;
};
std::string Client::getAccountName()
{
return m_AccountName;
};
std::string Client::getCharacterName()
{
return m_CharacterName;
};
//setters -- Account Name and Character Name are the only two that can be changed during a connection.
void Client::setAccountName(std::string in_AccountName)
{
m_AccountName = in_AccountName;
};
void Client::setCharacterName(std::string in_CharacterName)
{
m_CharacterName = in_CharacterName;
};
//Copy Constructor <--This defintely won't work and I know that, haha.
Client::Client(const Client& that)
{
m_Connection = new sf::TcpSocket();
*m_Connection = *that.m_Connection; // Cannot copy non-copyable
m_IPAddress = that.m_IPAddress;
m_CharacterName = that.m_CharacterName;
m_AccountName = that.m_AccountName;
};
Server Accept Function
void Server::AcceptConnections()
{
sf::TcpSocket* Socket = new sf::TcpSocket();
if( m_Listener.accept(*Socket) == sf::Socket::Done)
{
if(Socket != NULL )
{
std::string IPAddress = Socket->getRemoteAddress().toString();
if( m_Connections.find( IPAddress ) == m_Connections.end() )
{
std::cout << IPAddress;
std::cout << " Has Connected.";
std::endl( std::cout );
m_Connections.insert( std::make_pair(IPAddress, Client(Socket) ) );
}
}
}
};
First of all, whether you can use C++11 or not is a game changer.
In C++11, you have the concept of move. Unlike copying, moving is not about duplicating but about transferring. All Standard containers were adapted to non-copyable classes that are movable.
An example of a movable class:
class Client {
public:
Client(Client const&) = delete; // non copyable
Client& operator=(Client const&) = delete; // non copy assignable
Client(Client&&) = default; // movable
Client& operator=(Client&&) = default; // move assignable
private:
std::unique_ptr<sf::TcpSocket> _socket;
};
And your problem is solved.
If you are stuck in C++03 land, you are in for a bit of trouble. The simplest solution would be to use a manager class:
the manager owns the instance
users of the instance only ever manipulates references/pointers to it