what does the *(void**) means - c++

I have seen a class like this on the internet,
the head file
#ifndef _COMMON_ARRAY_OBJECT_POOL_H_
#define _COMMON_ARRAY_OBJECT_POOL_H_
#include <stdint.h>
namespace easynet
{
class ArrayObjectPool
{
public:
/** construct
* #param elem_size : element size;
* #param elem_num : element number
*/
ArrayObjectPool(uint32_t elem_size, uint32_t elem_num);
~ArrayObjectPool();
uint32_t ElemSize(){return m_ElemSize;}
uint32_t Capacity(){return m_ElemNum;}
bool IsEmpty(){return m_FreeHead==NULL;}
void* Get();
bool Recycle(void *elem);
private:
void *m_Elements;
void *m_End;
void *m_FreeHead;
uint32_t m_ElemSize;
uint32_t m_ElemNum;
};
}
#endif //_COMMON_ARRAY_OBJECT_POOL_H_
the cpp file
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "ArrayObjectPool.h"
namespace easynet
{
ArrayObjectPool::ArrayObjectPool(uint32_t elem_size, uint32_t elem_num)
{
m_ElemNum = elem_num;
if(elem_size < sizeof(void*))
m_ElemSize = sizeof(void*);
else
m_ElemSize = elem_size;
m_Elements = malloc(m_ElemSize*m_ElemNum);
m_End = (void*)((char*)m_Elements+m_ElemSize*m_ElemNum);
assert(m_Elements != NULL);
//construct list
int i;
void *node = m_Elements;
for(i=0; i<m_ElemNum-1; ++i)
{
*(void**)node = (void*)((char*)node+m_ElemSize);
node = *(void**)node;
}
*(void**)node = NULL;
m_FreeHead = m_Elements; //list head
}
ArrayObjectPool::~ArrayObjectPool()
{
free(m_Elements);
}
void* ArrayObjectPool::Get()
{
if(m_FreeHead == NULL)
return NULL;
void *temp = m_FreeHead;
m_FreeHead = *(void**)m_FreeHead;
return temp;
}
bool ArrayObjectPool::Recycle(void *elem)
{
if(elem<m_Elements || elem>=m_End)
return false;
*(void**)elem = m_FreeHead;
m_FreeHead = elem;
return true;
}
}
The question is I can't understand what does this means:
int i;
void *node = m_Elements;
for(i=0; i<m_ElemNum-1; ++i)
{
*(void**)node = (void*)((char*)node+m_ElemSize);
node = *(void**)node;
}
and what the *(void**) means? thanks!

It's treating the memory as if it were a union between the user's data type, and void*. When the blocks are in the free block list, the void* is used.
You can think of it as:
union ObjectInObjectPool
{
void* ptr_next_free_block;
UserType content;
};
and then that loop is basically doing:
ObjectInObjectPool* node = m_Elements;
for(i=0; i<m_ElemNum-1; ++i) {
node->ptr_next_free_block = node + 1;
node = node->ptr_next_free_block;
}
except that the programmer did by hand all the pointer arithmetic that the compiler's type checker usually does.

A void* is a pointer value that points to untyped memory. When you do *(void**)node = ..., what it is really doing is *node = .... However, with the latter, you are trying to assign something to a void which doesn't make sense with C++'s type system; you have to do as in the former and cast it to a void** so that *node will be a void*, not a void, and you can assign to it.
node = *(void**)node is just node = *node but forcing the type system to work. It just does "assign to node the value of the memory at *node interpreted as a void*".

Related

Why do I keep getting a read access violation? C++

I keep running through the program and changing around pointers and I don't see what I am missing. I keep getting a read access violation on line 42 of the .cpp file and I am genuinely confused on how.
Here is the .cpp file
#include "Graph.h";
void Graph::insertEdge(int from, int to, int weight)
{
if (from <= size && to <= size)
{
bool leave = true;
EdgeNode* current = vertices[from].edgeHead;
while (leave)
{
if (from == current->adjVertex || current == nullptr) //Read access violation here
{
current->weight = weight;
if (current == nullptr)
{
current->adjVertex = to;
current->nextEdge = nullptr;
}
leave = false;
}
else
current = current->nextEdge;
}
}
}
and here is the .h file
#include "Vertex.h";
#include <fstream>;
using namespace std;
class Graph
{
static const int MAX_VERTICES = 101;
struct EdgeNode
{
int adjVertex = 0;
int weight = 0;
EdgeNode* nextEdge = nullptr;
};
struct VertexNode
{
EdgeNode* edgeHead = nullptr;
Vertex* data = nullptr;
};
struct Table
{
bool visited;
int dist;
int path;
};
public:
void buildGraph(ifstream& in);
void insertEdge(int from, int to, int weight);
void removeEdge(int beginning, int end);
void findShortestPath();
void displayAll();
void display(int begin, int end);
private:
int size;
VertexNode vertices[MAX_VERTICES];
Table T[MAX_VERTICES][MAX_VERTICES];
};
I've been on this problem for multiple hours now and I can't seem to find the issue.
Probably instead of
if (from == current->adjVertex || current == nullptr)
you should first ensure the pointer is not null before dereferencing it.
if (current == nullptr || from == current->adjVertex)
then if current is null, the right-hand side of || operator won't be run.
HOWEVER, you will still have a problem because you also dereference current->weight inside the if-statement, even if current is null.

C++ Class pointer dynamic array deallocate problem

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define ROW 1
class Foo
{
public:
Foo()
{
this->dummy = new unsigned int[100];
}
~Foo()
{
delete[] this->dummy;
this->dummy = NULL;
}
unsigned int* dummy;
};
Foo** allocate()
{
Foo** foo_array = NULL;
foo_array = new Foo * [ROW]; //Create space for Foo addresses (row)
for (int i = 0; i < ROW; i++)
foo_array[i] = new Foo; //Create and allocate Foo for each address space(col)
return foo_array;
}
int deallocate(Foo* foo_array[ROW])
{
if (foo_array != NULL)
{
for (int i = 0; i < ROW; i++)
delete foo_array[i];
delete[] foo_array;
foo_array = NULL;
return 1;
}
return 0;
}
void main()
{
Foo** foo_array = NULL;
foo_array = allocate();
deallocate(foo_array);
if (foo_array != NULL)
printf("not null something wrong\n");
system("pause");
}
In main() function, foo_array should be pointed to NULL as soon as the deallocation is performed by the deallocate(Foo* foo_array[ROW]) function.
but, In deallocate(Foo* foo_array[ROW]) function,
foo_array = NULL;
It seems point to NULL by above syntax, however in main() function,
foo_array is not point to NULL.
so, I tried to change above syntax in deallocate(Foo* foo_array[ROW]) function,
foo_array = NULL; => (*foo_array) = NULL;
It spits out write access violation errors.
Where did it go wrong?
I don't see any reason to declare foo_array as pointer to pointer. In your code you are passing pointers by value. That means you can change what the pointers are pointing at but you can't change the values of the pointers. You can solve the problem using references.
#include <cstdio>
#define ROW 1
class Foo
{
public:
Foo()
{
this->dummy = new unsigned int[100];
}
~Foo()
{
delete[] this->dummy;
this->dummy = NULL;
}
unsigned int *dummy;
};
void allocate(Foo *&foo_array)
{
foo_array = new Foo[ROW];
}
void deallocate(Foo *&foo_array)
{
delete[] foo_array;
foo_array = nullptr;
}
int main()
{
Foo *foo_array = nullptr;
allocate(foo_array);
deallocate(foo_array);
if (foo_array != nullptr)
printf("not null something wrong\n");
}
Of course you can make your code much simpler using STL containers or smart pointers
The correct syntax would be foo_array = deallocate (foo_array); and your deallocate should return NULL.

How to set individual class array elements using class methods?

I'm using C++ and am trying to set an array element values with a setter method. The array is a class private member:
class Boo{
private:
int *x;
public:
Boo();
~Boo();
void setX(int,int);
int getX(int);
}
Boo::Boo(){
x = new int[1];
x = 0;
}
void Boo::setX(int value, int index){
//set condition for NULL
x[index] = value;
}
int Boo::getX(int index){
if(x[index] == NULL) {cout<<"invalid index"<<end; return;}
return x[index];
}
void test(){
Boo *p = new Boo();
p->setX(12,0);
cout<<p->getX(0)<<endl;
}
I been trying to test setting the values in 'x' starting with index '0' (like test()) but it crashes. I wanted to write a program where I run a loop counting up, and I set the array values. Can this be accomplish this way?
Do not use new in C++!
In this case, you should use std::vector<int>.
If you want to fix your code unless use std::vector,
#include <cstddef>
#include <iostream>
#include <stdexcept>
#include <memory>
using std::size_t;
class Boo {
private:
int *x;
size_t size;
size_t capacity;
public:
Boo();
~Boo();
void setX(int,size_t);
int getX(size_t);
};
Boo::Boo() : size(), capacity(1) {
this->x = new int[1];
//x = 0;//DO NOT ASSIGN NULL POINTER!!!!
}
Boo::~Boo() noexcept {
delete[] x;
}
void Boo::setX(int value, size_t index){
if(this->capacity <= index) throw std::out_of_range("Boo::setX");//YOU MUST CHECK RANGE
this->x[index] = value;
++this->size;
}
int Boo::getX(size_t index){
if(this->size <= index) throw std::out_of_range("Boo::getX");//YOU MUST CHECK RANGE
return x[index];
}
void test(){
auto p = std::make_unique<Boo>();
p->setX(12,0);
std::cout << p->getX(0) << std::endl;
}
int main(){
test();
}
http://melpon.org/wandbox/permlink/aIhwC5c9o1q8ygIo
Boo::Boo()
{
x = new int[1];
x = 0;
}
you are not able to set value in an array because after initializing with memory, you have set the pointer of an array to null in constructor.
please use x[0] = 0; instead of x = 0;

Initializing an empty Stack

I'm trying to initialize an empty stack of size 3, but my program is not letting me put NULL into even 1 of the elements. I'm not sure what the problem is. The program just stops working when it attempts to initialize one of elements.
Stack300::Stack300 ()
{
for (int i = 0; i < 3; i++)
{
stackArray[i] = '\0';
//stackArray[i] = i;
}
top = 0;
return;
}
My .h file.
#ifndef CONGERA2_H
#define CONGERA2_H
typedef float Element300;
class Stack300
{
public:
Stack300 ();
Stack300 (const int);
Stack300 (Stack300 &old);
~Stack300();
void push300(const Element300);
Element300 pop300();
void viewTB300();
void viewBT300();
private:
const int MAX_STACK = 80;
Element300 * stackArray;
int top;
};
#endif
And my main file.
#include <iostream>
#include "congera2.h"
using namespace std;
int main()
{
Element300 temp1 = 1.1;
Element300 temp2 = 2.2;
Element300 temp3 = 3.3;
Stack300 myStack;
Stack300 myStack2 (myStack);
/* myStack.push300(temp1);
myStack.push300(temp2);
myStack.push300(temp3);*/
cout << "hello";
return 0;
}
In your constructor, you are never allocating any memory to the 'stackArray' member. The following line would accomplish initializing a dynamic array of 3 floating point integers.
stackArray = new float[3];
You will then want to make sure this memory is deallocated in the destructor as well.
Edited to add some useful resources; these pages do a good job explaining the concept behind pointers and dynamic memory allocation:
Pointers,
Dynamic Memory

how to convert this code from Dijkstra to Astar?

So I have a project of which I want to switch to Astar due to speed reasons.
But C++ is not my strongest point. Could anyone help me (or tell me how to do the..) converting the algorythm from Dijkstra to Astar?
I found this Astar implementation:
http://code.google.com/p/a-star-algorithm-implementation/
But I don't know how to use it with my existing code.
Here is the graph file which got the algorithm:
#include "Graph.h"
#include <iostream>
#include <algorithm>
#include <stack>
Graph::Graph(void)
{
}
Graph::~Graph(void)
{
while(!mNodes.empty())
{
delete mNodes.back();
mNodes.pop_back();
}
}
void Graph::addNode(int name, bool exists, Node** NodeID )
{
Node* pStart = NULL;
mNodes.push_back(new Node(name,exists));
std::vector<Node*>::iterator itr;
itr = mNodes.begin()+mNodes.size()-1;
pStart = (*itr);
if(exists == true)pStart->DoesExist_yes();
*NodeID = pStart;
}
void Graph::connect_oneway(Node* pFirst, Node* pSecond, int moveCost)
{
if(pFirst != NULL && pSecond != NULL)
{
pFirst->createEdge(pSecond, moveCost);
}
}
#define MAX_NODES (32768)
#define MAX_CONNECTIONS (5)
#include <time.h>
int * Graph::findPath_r(Node* pStart, Node* pEnd)
{
int *arr = new int[MAX_NODES+2];
for (int i=0; i<MAX_NODES; i++)
arr[i] = -1;
arr[0] = 0;
if(pStart == pEnd)
{
return arr;
}
std::vector<Node*> openList;
openList.push_back(pStart);
Node* pCurrNode = NULL;
while(!openList.empty())
{
//Get best node from open list (lowest F value).
//Since we sort the list at the end of the previous loop we know
//the front node is the best
pCurrNode = openList.front();
//Exit if we're are the goal
if(pCurrNode == pEnd)
break;
//Remove the node from the open list and place it in the closed
openList.erase(openList.begin());
pCurrNode->setClosed(true); //We use a flag instead of a list for speed
//Test all of the edge nodes from the current node
std::vector<Edge*>* pEdges = pCurrNode->getEdges();
Node* pEdgeNode = NULL;
for(std::vector<Edge*>::iterator i = pEdges->begin(); i != pEdges->end(); ++i)
{
pEdgeNode = (*i)->pNode;
//If it's closed we've already analysed it
if(!pEdgeNode->getClosed() && pCurrNode->DoesExist() == true)
{
if(!inList(pEdgeNode,&openList))
{
openList.push_back(pEdgeNode);
pEdgeNode->setGCost(pCurrNode->getGCost()+(*i)->moveCost);
pEdgeNode->calcFCost();
pEdgeNode->setParent(pCurrNode);
}
else
{
//If this is a better node (lower G cost)
if(pEdgeNode->getGCost() > pCurrNode->getGCost()+(*i)->moveCost)
{
pEdgeNode->setGCost(pCurrNode->getGCost()+(*i)->moveCost);
pEdgeNode->calcFCost();
pEdgeNode->setParent(pCurrNode);
}
}
}
}
//Place the lowest F cost item in the open list at the top, so we can
//access it easily next iteration
std::sort(openList.begin(), openList.end(), Graph::compareNodes);
}
//Make sure we actually found a path
if(pEnd->getParent() != NULL)
{
//Output the path
//Use a stack because it is LIFO
std::stack<Node*> path;
while(pCurrNode != NULL)
{
path.push(pCurrNode);
pCurrNode = pCurrNode->getParent();
}
int counter = 0;
arr[1] = 0;
while(!path.empty())
{
arr[counter+2] = path.top()->getName();
counter++;
arr[1] += path.top()->getGCost();
path.pop();
}
arr[0] = counter;
return arr;
}
return arr;
}
bool Graph::inList(Node* pNode, std::vector<Node*>* pList)
{
for(std::vector<Node*>::iterator i = pList->begin(); i != pList->end(); ++i)
{
if((*i) == pNode)
{
return true;
}
}
return false;
}
bool Graph::compareNodes(Node* pFirst, Node* pSecond)
{
return pFirst->getFCost() < pSecond->getFCost();
}
void Graph::reset(void)
{
for(std::vector<Node*>::iterator i = mNodes.begin(); i != mNodes.end(); ++i)
{
(*i)->reset();
}
}
The function for finding the path is this one:
Graph::findPath_r
What I really want to do is preserve the edges (because they decide if the road is both or one-way).
Here are the other files:
Graph.h
#ifndef _GRAPH_H_
#define _GRAPH_H
#include "Node.h"
class Graph
{
public:
Graph(void);
~Graph(void);
//void addNode(int name, bool exists);
void addNode(int name, bool exists, Node** NodeID );
void connect_oneway(int ppFirst, int ppSecond, int moveCost);
void connect_oneway(Node* pFirst, Node* pSecond, int moveCost);
//int * findPath_r(int start, int end);
int * findPath_r(Node* pStart, Node* pEnd);
void reset(void);
private:
void findNodesx(int firstName, Node** ppFirstNode);
bool inList(Node* pNode, std::vector<Node*>* pList);
static bool compareNodes(Node* pFirst, Node* pSecond);
std::vector<Node*> mNodes;
};
#endif
Node.h
#ifndef _NODE_H_
#define _NODE_H_
#include <string>
#include <vector>
//Forward declare Node so Edge can see it
class Node;
struct Edge
{
Edge(Node* node, int cost) : pNode(node), moveCost(cost){}
Node* pNode;
int moveCost;
};
class Node
{
public:
Node(void);
Node(int name, bool exists);
~Node(void);
void createEdge(Node* pTarget, int moveCost);
void setGCost(int cost);
void setClosed(bool closed);
void setParent(Node* pParent);
int getGCost(void);
int getFCost(void);
bool getClosed(void);
Node* getParent(void);
int getName(void);
bool DoesExist(void);
bool DoesExist_yes(void);
std::vector<Edge*>* getEdges(void);
void calcFCost(void);
void reset(void);
private:
int mGCost;
int mTotal;
bool mClosed;
Node* mpParent;
int mName;
bool mHeur;
std::vector<Edge*> mEdges;
};
#endif
Node.cpp
#include "Node.h"
Node::Node(void)
{
}
Node::Node(/*const std::string&*/int name, bool exists) : mGCost(0), mTotal(0), mClosed(false), mpParent(NULL), mName(name), mHeur(exists)
{
}
Node::~Node(void)
{
while(!mEdges.empty())
{
delete mEdges.back();
mEdges.pop_back();
}
}
int Node::getName(void)
{
return mName;
}
void Node::createEdge(Node* pTarget, int moveCost)
{
mEdges.push_back(new Edge(pTarget, moveCost));
}
void Node::setClosed(bool closed)
{
mClosed = closed;
}
bool Node::getClosed(void)
{
return mClosed;
}
std::vector<Edge*>* Node::getEdges(void)
{
return &mEdges;
}
int Node::getGCost(void)
{
return mGCost;
}
void Node::setGCost(int cost)
{
mGCost = cost;
}
void Node::calcFCost(void)
{
mTotal = mGCost;
}
void Node::setParent(Node* pParent)
{
mpParent = pParent;
}
int Node::getFCost(void)
{
return mTotal;
}
bool Node::DoesExist(void)
{
return mHeur;
}
bool Node::DoesExist_yes(void)
{
mHeur = true;
return true;
}
Node* Node::getParent(void)
{
return mpParent;
}
void Node::reset(void)
{
mGCost = 0;
mTotal = 0;
mClosed = false;
mpParent = NULL;
}
You mentioned a library on GoogleCode. It is node clear what you want to do with, and I think the best is to write your implementation yourself.
First, you should know that Dijsktra is a special case of A*. In A*, you have an heuristic, named h; A* = possible implementation of Dijsktra when h is the null function.
Then, about your implementation, let's start with Node. It will need the following functions:
constructor, destructor
create/get edge
set/get parent
set/is closed (for speed)
set/get GCost
set/get FCost
set/is obstacle (name way more descriptive than 'DoesExist')
set/get position
reset
// optional method:
get name
Hopefully, this part of your code won't change a lot. The heuristic code will be placed in the pathfinder. The Edge class is left untouched.
Now the big one: Graph. You won't need to delete any of your public methods.
You will need a heuristic method. For the implementation which will be described, you will need an admissible consistent heuristic:
it must not over-estimate the distance to the goal (admissible)
it must be monotone (consistent)
The general case signature is int getHCost(Node* node);. If you always return 0, you will have a Dijsktra algorithm, which is not what you want. Here we will take the euclidiean distance between the node and the goal. Slower to compute than manhattan distance, but better results. You can change this afterwards.
int getHCost(Node* node, Note* goal);
This implies you must place your nodes in the 3d space. Note that the heuristic is a heuristic, ie, an estimation of the distance.
I won't write the code. I will write some pseudo-code adapted to your situation. The original pseudocode is located on the Wikipedia A* page. This pseudo-code is your findPath_r function:
function A*(start,goal)
set all nodes to not closed // The set of nodes already evaluated.
openset = {start} // The set of tentative nodes to be evaluated, initially containing the start node
start.gcost = 0 // Cost from start along best known path.
// Estimated total cost from start to goal through y.
start.fcost = start.gcost + getHCost(start, goal)
while openset is not empty
current = the node in openset having the lowest f_cost (usually the first if you use a sorted list)
if current == goal
return construct_path(goal)
remove current from openset
current.closed = true
for each neighbor in (node connected by edge in current.edges) // Here is the condition for one-way edges
if neighbor.closed or neighbor.obstacle
continue
gcost = current.gcost + dist_between(current,neighbor) // via edge distance
if neighbor not in openset
add neighbor to openset
neighbor.parent = current
neighbor.gcost = gcost
neighbor.fcost = neighbor.gcost + getHCost(neighbor, goal)
else if gcost < neighbor.gcost
neighbor.parent = current
neighbor.gcost = gcost
neighbor.fcost = neighbor.gcost + getHCost(neighbor, goal)
update neighbor position in openset
return failure
function construct_path(current_node)
std::vector<Node*> path
while current_node != 0
path.push_front(current_node)
current_node = current_node.parent
return path
The implementation above use one-way edges.
You were able to write Dijsktra algorithm in C++, so writing this pseudocode in C++ shouldn't be a problem.
Second part, performances. First, measure ;).
I have some hints that can improve performances:
use a memory pool for allocation deallocation
use an intrusive list for the open list (you can also make it auto-sorted with this technique)
I advise you to read A* for beginners, which is a useful reading, even if you don't use tilemap.