Which smart pointer to use in Stack implementation? - c++

From what I've understood correctly:
scoped_ptr: no overhead, cannot be copied or moved.
unique_ptr: no overhead, cannot be copied, can be moved.
shared_ptr: some overhead (reference counting), can be copied.
Having said that, if there is a need for several owners, then shared_ptr should be used.
Now, in this program below which is a simple implementation of stack in C++. I don't understand which type of smart pointer should be used.
The reason I'm asking this question because both unique_ptr as well as shared_ptr cannot be copied and that is exactly what I'm doing in this implementation of simple stack. I've commented out //HERE in the program where I'm using C++ pointers and if you read the program properly you'll see how the data is getting copied in pretty much all the functions.
GameStateStack.h
#ifndef _H_GAMESTATE_
#define _H_GAMESTATE_
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <memory>
class node
{
public:
std::string gameState;
node * nextGameState; // HERE
};
class GameStateStack
{
private:
node * _topState; // HERE
void Destory();
public:
int gameStatesCount;
void PushGameState(std::string element);
void PopGameState();
std::string CurrentGameState();
GameStateStack();
~GameStateStack();
};
extern GameStateStack state;
#endif
GameStateStack.cpp
#include <iostream>
#include <stdlib.h>
#include <string>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <memory>
#include "GameStateStack.h"
#include "template.h"
GameStateStack state;
GameStateStack::GameStateStack()
{
_topState = NULL;
gameStatesCount = 0;
}
GameStateStack::~GameStateStack()
{
}
void GameStateStack::PushGameState(std::string gameStateName)
{
node *newTopState = new node; // HERE
if (_topState == NULL)
{
newTopState->gameState = gameStateName;
newTopState->nextGameState = NULL;
_topState = newTopState;
gameStatesCount++;
}
else
{
newTopState->gameState = gameStateName;
newTopState->nextGameState = _topState;
_topState = newTopState;
gameStatesCount++;
}
}
void GameStateStack::PopGameState()
{
if (_topState == NULL)
std::cout << "Error: no gamestates available to pop";
else
{
node * old = _topState; // HERE
_topState = _topState->nextGameState;
delete(old);
gameStatesCount--;
}
}
std::string GameStateStack::CurrentGameState()
{
node *temp; // HERE
temp = _topState;
return temp->gameState;
}
void GameStateStack::Destory()
{
node *abc; // HERE
delete _topState;
delete abc->nextGameState;
}

Here is how your stack could be implemented using a std::unique_ptr. Note the use of std::move() to re-assign the std::unique_ptr leaving the original pointing at nothing.
Also, instead of if(topState == NULL) I have used the more idiomatic if(topState). A std::unique_ptr returns true if it points somewhere or false if it does not.
Also standard C++ dictates that we should not begin variable names with a leading _.
#include <string>
#include <memory>
#include <iostream>
struct node
{
std::string gameState;
std::unique_ptr<node> nextGameState;
~node()
{
std::cout << "deleting: " << gameState << '\n';
}
};
class GameStateStack
{
// should not use _ to begin variable names in std C++
std::unique_ptr<node> topState;
int gameStatesCount;
public:
GameStateStack();
void PushGameState(std::string gameStateName);
void PopGameState();
std::string CurrentGameState();
void Destory();
};
GameStateStack::GameStateStack()
: gameStatesCount(0) // initialize here
{
//topState = NULL; // no need to initialize unique_ptr
//gameStatesCount = 0; // not here
}
void GameStateStack::PushGameState(std::string gameStateName)
{
std::unique_ptr<node> newTopState(new node);
newTopState->gameState = gameStateName;
newTopState->nextGameState = std::move(topState);
topState = std::move(newTopState);
gameStatesCount++;
}
void GameStateStack::PopGameState()
{
if(!topState)
std::cout << "Error: no gamestates available to pop";
else
{
topState = std::move(topState->nextGameState);
gameStatesCount--;
}
}
std::string GameStateStack::CurrentGameState()
{
if(topState)
return topState->gameState;
return "error: nothing on stack"; // error
}
void GameStateStack::Destory()
{
// deleting topState will first destroy the pointed to
// node's own unique_ptr<node> nextGameState
// which in turn will first delete its own nextGameState etc...
topState.reset();
}
int main()
{
GameStateStack stack;
std::cout << "\ndestroy test" << '\n';
stack.PushGameState("a");
stack.PushGameState("b");
stack.PushGameState("c");
stack.PushGameState("d");
stack.PushGameState("e");
stack.PushGameState("f");
stack.Destory();
std::cout << "\npush-pop test" << '\n';
stack.PushGameState("a");
stack.PushGameState("b");
stack.PushGameState("c");
std::cout << stack.CurrentGameState() << '\n';
stack.PopGameState();
stack.PushGameState("d");
stack.PushGameState("e");
std::cout << stack.CurrentGameState() << '\n';
stack.PopGameState();
std::cout << stack.CurrentGameState() << '\n';
stack.PopGameState();
std::cout << stack.CurrentGameState() << '\n';
stack.PopGameState();
std::cout << stack.CurrentGameState() << '\n';
stack.PopGameState();
std::cout << stack.CurrentGameState() << '\n';
stack.PopGameState();
}

Here an unique_ptr is perfectly fine, especially if you return the CurrentGameState by value as you are doing.
Your top should be a unique_ptr<node>& but since there will be no state at the beginning you could use a std::reference_wrapper to wrap it.
Of course if you plan to return a game state by reference or pointer things will change, because popping a state would invalidate the contained state (unless it's dynamically allocated and then set).

Related

Working with std::unique_ptr and std::queue

Maybe it's my sinuses and that I fact that I just started learning about smart pointers today I'm trying to do the following:
Push to the queue
Get the element in the front
Pop the element (I think it will automatically deque once the address out of scope)
Here is the error
main.cpp:50:25: error: cannot convert ‘std::remove_reference&>::type’ {aka ‘std::unique_ptr’} to ‘std::unique_ptr*’ in assignment
50 | inputFrame = std::move(PacketQueue.front());
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
| |
| std::remove_reference<std::unique_ptr<MyObject::Packet>&>::type {aka std::unique_ptr<MyObject::Packet>}
Here is the code
#include <iostream>
#include <memory>
#include <queue>
using namespace std;
class MyObject
{
public:
struct Packet
{
uint8_t message;
uint8_t index;
};
void pushToQueue(void);
void FrontOfQueue(std::unique_ptr<Packet> *inputFrame);
private:
std::queue<std::unique_ptr<Packet>> PacketQueue;
};
void MyObject::pushToQueue(void)
{
Packet frame;
static int counter = 1;
frame.message = counter;
frame.index =counter;
counter++;
std::unique_ptr<Packet> passthru_ptr = std::make_unique<Packet>(std::move(frame));
PacketQueue.push(std::move(passthru_ptr));
cout<<"Pushed to queue\n" ;
}
void MyObject::FrontOfQueue(std::unique_ptr<Packet> *inputFrame)
{
inputFrame = std::move(PacketQueue.front());
}
int main()
{
cout<<"Hello World\n";
MyObject object;
object.pushToQueue();
object.pushToQueue();
{
// Scope
std::unique_ptr<MyObject::Packet> *frame;
object.FrontOfQueue(frame);
cout<< frame << endl;
}
{
// Scope
std::unique_ptr<MyObject::Packet> *frame2;
object.FrontOfQueue(frame2);
cout<< frame2 << endl;
}
return 0;
}
Link to the code (Online Compiler)
If I got your aim correctly, you definitely want
std::unique_ptr<MyObject::Packet> MyObject::FrontOfQueue()
{
auto rv = std::move(PacketQueue.front());
PacketQueue.pop();
return rv;
}
// ...
std::unique_ptr<MyObject::Packet> frame = object.FrontOfQueue();
Notice, no raw pointers are used.
I think it will automatically deque once the address out of scope.
This assumption is wrong. Nothing is dequeued until .pop() is called.
Here is my example with some extra logging to show whats going on.
includes an introduction of returning const references as well.
Live demo : https://onlinegdb.com/P2nFkdMy0
#include <iostream>
#include <memory>
#include <queue>
#include <string>
//-----------------------------------------------------------------------------
// do NOT use : using namespace std;
//-----------------------------------------------------------------------------
struct Packet
{
// moved to uint32_t for std::cout reasons.
// uint8_t is displayed as(special) characters
std::uint32_t index;
std::uint32_t message;
Packet() :
index{ next_index() },
message{ index }
{
std::cout << "created packet : " << index << "\n";
}
~Packet()
{
std::cout << "destroyed packet : " << index << "\n";
}
// small helper to not have to declare the static variable seperatly
static std::uint8_t next_index()
{
static int counter;
return counter++;
}
};
//-----------------------------------------------------------------------------
class MyObject
{
public:
void push_packet();
std::unique_ptr<Packet> pop_packet();
// this function returns a const reference (observation only)
// of the packet at the front of the queue
// while leaving the unique pointer on the queue (no moves needed
// packet will still be owned by the queue)
const Packet& front();
private:
std::queue<std::unique_ptr<Packet>> m_queue;
};
void MyObject::push_packet()
{
std::cout << "push_packet\n";
// push a packet
m_queue.push(std::make_unique<Packet>());
std::cout << "push_packet done...\n";
}
std::unique_ptr<Packet> MyObject::pop_packet()
{
std::unique_ptr<Packet> packet = std::move(m_queue.front());
m_queue.pop();
return packet;
}
const Packet& MyObject::front()
{
return *m_queue.front();
}
//-----------------------------------------------------------------------------
int main()
{
const std::size_t n_packets = 3ul;
MyObject object;
for (std::size_t n = 0; n < n_packets; ++n)
{
std::cout << "pushing packet\n";
object.push_packet();
}
for (std::size_t n = 0; n < n_packets; ++n)
{
std::cout << "packet at front : ";
std::cout << object.front().index << "\n";
std::cout << "popping front\n";
auto packet_ptr = object.pop_packet();
std::cout << "popped packet : " << packet_ptr->index << "\n";
}
return 0;
}

Is it possible to use std::make_unique in a class constructor and `this` pointer?

I am trying to use unique_ptr instead of raw pointers for components that are assigned to an actor class.
#include <iostream>
#include <memory>
#include <utility>
#include <algorithm>
#include <vector>
class Component;
class Actor
{
public:
void AddComponent(std::unique_ptr<Component> component)
{
std::cout << "Add component\n";
mComponents.push_back(std::move(component));
}
void RemoveComponent(Component* component)
{
std::cout << "Removing Component...\n";
auto iter = std::find_if(mComponents.begin(), mComponents.end(),[&](const auto& e){ return e.get() == component;});
if(iter != mComponents.end())
{
mComponents.erase(iter);
std::cout << "Removed from vector \n";
}
}
void ListComponents()
{
for(const auto& element : mComponents)
{
std::cout << "Component:" << element.get() << "\n";
}
}
private:
std::vector<std::unique_ptr<Component> > mComponents;
};
class Component
{
public:
Component(Actor* actor) : mOwner(actor) {actor->AddComponent(std::make_unique<Component>(*this));}
virtual ~Component() { std::cout << this << ":Destroyed \n"; }
private:
Actor* mOwner = nullptr;
};
int main(int argc, char* argv[])
{
Actor Actor1;
auto c1 = Component(&Actor1);
auto c2 = Component(&Actor1);
Actor1.ListComponents();
}
Is there a way to assign the this pointer to a unique_ptr, or am I right that I need to use a factory function of some kind?
Thanks!
EDIT: Corrected Code:
#include <iostream>
#include <memory>
#include <utility>
#include <algorithm>
#include <vector>
class Component;
class Actor
{
public:
void AddComponent(std::unique_ptr<Component> component)
{
std::cout << "Add component\n";
mComponents.push_back(std::move(component));
}
void RemoveComponent(Component* component)
{
std::cout << "Removing Component...\n";
auto iter = std::find_if(mComponents.begin(), mComponents.end(),[&](const auto& e){ return e.get() == component;});
if(iter != mComponents.end())
{
mComponents.erase(iter);
std::cout << "Removed from vector \n";
}
}
void ListComponents()
{
for(const auto& element : mComponents)
{
std::cout << "Component:" << element.get() << "\n";
}
}
private:
std::vector<std::unique_ptr<Component> > mComponents;
};
class Component
{
public:
Component(Actor* actor) : mOwner(actor) {actor->AddComponent(std::unique_ptr<Component>(this));}
virtual ~Component() { std::cout << this << ":Destroyed \n"; }
private:
Actor* mOwner = nullptr;
};
int main(int argc, char* argv[])
{
Actor Actor1;
auto c1 = new Component(&Actor1);
auto c2 = new Component(&Actor1);
Actor1.ListComponents();
}
There are at least three issues here.
There are various syntax errors (missing declaration of Component before the definition of Actor, typos, ... I'll ignore them now they are mentionned.
The if you have any pointer, you can build a unique_ptr from it which will handle the lifetime of the object. That's not made with make_unique but with the constructor:
owner->AddComponent(std::unique_ptr<Component>(this));
You can do that but the unique_pointer will manage the lifetime of the Component. So that means that nothing else should and you have to avoid that, especially temporaries and stack allocated one. So you'll have to replace:
c1 = Component(&Actor1);
c2 = Component(&Actor1);
by something like:
new Component(&Actor1);
new Component(&Actor1);
There are various way to enforce that so that mistakes are detected at compilation, but I'll not go into them.

Why do i get a linker error,when everything is in one file?

I get a LNK 2019 error in VS.
I have read a couple of similiar problems,but could not understand what i should do.As much as i understood VS can't find the template class code for some reason.I am not sure.
#include "pch.h"
#include <iostream>
#include <assert.h>
template<typename T>
struct item {
item* pointer = nullptr;
T value;
};
template <typename T>
class stack {
private:
item<T>* top;
public:
stack() { top = nullptr; };
~stack();
void push(const T& s) {
item<T>* p = top;
top = new item<T>;
assert(top != nullptr);
top->value = s;
top->pointer = p;
std::cout << "The item has been pushed." << std::endl;
}
void pop() {
T s;
if (!top) {
std::cout << "The stack is empty." << std::endl;
}
else {
s = top->value;
item<T>* p = top;
top = top->pointer;
delete p;
std::cout << "The item has been popped." << std::endl;
}
};
void check() {
if (!top) { std::cout << "The stack is empty." << std::endl; }
else { std::cout << "It has elements in it." << std::endl; }
}
};
int main()
{
stack<int> test;
return 0;
}
I want afterwards to be able to push and pop elements.So that i can continue on with my project.
You have declared a destructor for stack here:
~stack();
but you don't define it. Change the above to
~stack() { /* Clean up resources here. */ }
and it should work.
In C++, if you declare a destructor, you have to define it. Even if the destructor is pure virtual, you still have to define it or else you'll get linker error, as is the case here. If you are fine with the default destructor, but still want to declare it for some reason, for instance, to make it virtual, you can use the keyword default:
virtual ~stack() = default;
You can learn more about the default keyword here.

Is this a good way to store, iterate and delete pointers in an std::vector?

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <vector>
using namespace std;
struct delete_ptr
{
template<typename T>
void operator()(T*& t)
{
delete t;
t = 0;
}
};
struct is_null_ptr
{
template<typename T>
bool operator()(T*& t)
{
return t == 0;
}
};
struct A
{
static void removeDead(A*& a)
{
if(a and a->dead)
delete_ptr()(a);
}
static void killSome(A* a)
{
if(a and a->isDead() == false and rand()%100 == 0)
{
static int counter = 0;
cout << "Kill___" << ++counter << endl;
a->kill();
}
}
static void reviveSome(A* a)
{
if(a and a->isDead() and rand()%3 == 0)
{
static int counter = 0;
cout << "Revive___" << ++counter << endl;
a->revive();
}
}
A():dead(false)
{
}
virtual ~A()
{
static int counter = 0;
cout << "Dtor___" << ++counter << endl;
}
bool isDead(){return dead;}
void kill(){dead = true;}
void revive(){dead = false;}
bool dead;
};
int main()
{
srand(time(0));
vector<A*> as;
for(int i = 0; i < 200; ++i)
{
A* a = new A;
as.push_back(a);
}
for_each(as.begin(),as.end(),A::killSome);
for_each(as.begin(),as.end(),A::reviveSome);
for_each(as.begin(),as.end(),A::removeDead);
as.erase( std::remove_if(as.begin(),as.end(),is_null_ptr()),as.end());
cout << as.size() << endl;
for_each(as.begin(),as.end(),delete_ptr());
as.clear();
return 0;
}
It allocates them, and prints the right output but I'm not sure this is the right thing I'm doing. I was just trying to use pointers in a vector and delete them when a certain condition happens, without using boost or c++11.
So what do you think about it?
Since the only smart pointer present in the current STL (auto_ptr) cannot be used in containers, I would say your way is a good one under the given conditions.
You could think about implementing your own unique_ptr or shared_ptr however.
PS: There are many reasons to use pointers instead of the actual objects in a container, one is polymorphism. Another one is that the actual objects are already stored somewhere else (think of an index structure to already stored objects).

Singleton class for moving heap to stack

I have written some class that moves heap allocated stuff to stack (hopefully :) ). This calss is singleton because only this class should be responsible for holding and managing part of stack. My question is: Is my code correct? Code is correct in the sense of programming (no compile errors, no memory errors and leaks (checked by valgrind)). But does the code really moves heap to stack? Here's the code:
stack.hpp:
class CStack{
public:
void* getAlloc(long);
static CStack* Instance();
private:
static bool _data[5*sizeof(double)];
static CStack* m_pInstance;
CStack(){};
CStack(const CStack&);
CStack& operator=(const CStack&);
};
stack.cpp:
#include <iostream>
#include "stack.hpp"
CStack* CStack::m_pInstance = 0;
bool CStack::_data[ 5*sizeof(double) ] = { 1 };
CStack* CStack::Instance(){
if (!m_pInstance)
m_pInstance = new CStack;
return m_pInstance;
}
void* CStack::getAlloc(long size){
std::cout << " CStack::getAlloc, " << _data << std::endl;
_pos+=size;
return &_data[0];
}
store.hpp
class CStore{
public:
CStore();
double* myAddr();
void toStack();
void out();
~CStore();
private:
double *_data;
bool _stack;
};
store.cpp:
#include <iostream>
#include <cstring>
#include "store.hpp"
#include "stack.hpp"
CStore::CStore(){
_data = new double[4];
_data[0] = 0.1;
_data[1] = 1.1;
_data[2] = 2.1;
_data[3] = 3.1;
_stack = 0;
}
double* CStore::myAddr(){ return _data; }
void CStore::toStack(){
double *tmp;
tmp = (double*)CStack::Instance() -> getAlloc(4*sizeof(double));
memcpy(tmp, _data, 4*sizeof(double));
delete [] _data;
_data = tmp;
_stack = 1;
}
CStore::~CStore(){
if (!_stack)
delete [] _data;
}
void CStore::out(){
std::cout << _data[0] << " " << _data[1] << " " << _data[2] << " " << _data[3] << std::endl;
}
main.cpp:
#include <iostream>
#include "stack.hpp"
#include "store.hpp"
using namespace std;
int main(){
CStack::Instance();
CStore a;
double stack;
cout << &stack << endl;
cout << "Adresa a " << a.myAddr() << endl;
a.out();
a.toStack();
cout << "Adresa a " << a.myAddr() << endl;
a.out();
return 0;
}
No it's utter nonsense.
First of all this code doesn't even use the stack (as long as we are speaking of the execution stack), and you clearly misunderstood the Singleton desing pattern.
You use Singleton, when you only need a single instance in your program, but you want to grant access to all functions to that single instance. Its like a global variable, but you can restrict the access.
Second, if you need to use casting in C++ like:
tmp = (double*)CStack::Instance() -> getAlloc(4*sizeof(double));
You've clearly gone wrong. Don't use void* in C++ for now. You can use it later, when you've gotten better, not for now.
The main question WHY do you wan't to move variables to the stack? if you simply want to allocate dynamicly, why still limiting it to the scope, use smart pointers, like std::auto_ptr.
if you want to create a stack, and use that to store your doubles you can write:
#include <vector>
int foo()
{
std::vector<double> stack;
// push values on the stack
stack.push_back(1.1);
stack.push_back(1.2);
stack.push_back(1.3);
// remove values from the stack
stack.pop_back();
stack.pop_back();
stack.pop_back();
}