I am trying to make a network application. Its class blueprint is roughly like this-
class Node
{
public:
// member functions
private:
int nodeID;
// other members
};
class NodeNetwork
{
public:
// member functions
private:
Node nodeArray[MAX_NODES];
// other members
};
Here, the Node class will deal with each node and the NodeNetwork is used to deal with the complete network.
The actual number of nodes in nodeArray can vary from 0 to MAX_NODES during runtime, i.e., it may not always be MAX_NODES, the number of nodes can be increased or decreased during runtime. Moreover, when the program starts the number will always be 0, after that it will start increasing.
I am using Node nodeArray[MAX_NODES];, but I think it's a serious wastage of space as not always I will have MAX_NODES nodes at runtime. So I am looking for ways to optimize it. I want it so that it starts with a zero-length array, but the size can be increased or decreased subjected to the above constraints based on the nodes added or removed at runtime. I researched on the internet but did not find any concrete answer.
I hope someone can help me solve this problem, thanks in advance.
You can use dynamically array allocation for this purpose:
int* arr = new int[5];
..and anytime you wish to change the number of elements:
int size = 5;
int* arr = new int[size] {};
int* new_arr = new int[size + 1];
for (int i = 0; i < size; i++)
{
new_arr[i] = arr[i];
}
delete[] arr;
arr = new_arr;
// Now arr has a storage capacity of 6 elements
..so for your case you can write:
Node* nodeArray = nullptr; // nullptr == null pointer
But this can take a lot of time for huge arrays.
So preferably, you can use std::vector:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec{ 1, 2, 3, 4, 5 };
vec.push_back(6); //Insert a new element
std::cout << vec[0]; // Accessing an element is the same as an array
}
..so for your case:
// {} is just for initialization, not exactly mandatory
std::vector<Node> nodeArray{};
You can use std::vector instead of array. That is, you can make the data member nodeArray to be a std::vector<Node> as shown below.
#include <iostream>
#include<vector>
class Node
{
public:
//constructor for initializing nodeID data member
Node(int pnodeID): nodeID(pnodeID)
{
}
//getter for nodeId
int getId() const
{
return nodeID;
}
private:
//always initialize built in type in local/block scope so that they don't have indeterminate value
int nodeID = 0;
// other members
};
class NodeNetwork
{
public:
// member function to add Node
void addNode(const Node& n)
{
nodeArray.push_back(n);
}
//member function to print out the current nodes
void display() const
{
std::cout<<"Network has the following nodes: "<<std::endl;
for(const Node& elem: nodeArray)
{
std::cout<<elem.getId()<<std::endl;
}
}
private:
std::vector<Node> nodeArray; //used std::vector instead of array
// other members
};
int main()
{
//create Node objects
Node node1{1};
Node node2{2};
Node node3{3};
NodeNetwork network1;
//add node1 into the network1's nodeArray data member
network1.addNode(node1);
//add node2 into the network1's nodeArray data member
network1.addNode(node2);
//display all nodes into network1
network1.display();
return 0;
}
In the above demo we have added elements into the nodeArray data member by using std::vector::push_back member function.
The output of the above program can be seen here:
Network has the following nodes:
1
2
Related
I tried initializing a 2D vector with a constructor in 3 different ways but always get an
"error: no matching function to call"
Could you tell me where I am wrong?
class Node
{
public:
int to;
int length;
Node(int to, int length) : to(to), length(length){}
};
class Graph
{
public:
vector<vector<Node>> nodes_list;
int n;
Graph();
};
Graph::Graph(){
nodes_list = vector<vector<Node> >(n, vector<Node>(n,0x3fffffff));
}
vector<Node>(n,0x3fffffff);
is (roughly) equivalent to:
vector<Node> v;
for ( size_t i = 0; i < n; i++ )
{
v.push_back(Node(0x3fffffff));
}
As your Node class doesn't have a constructor taking a single integer this fails to compile. The correct code is:
vector<Node>(n,Node(0x3fffffff,0));
By the way I assume you have using namespace std; in your header for Graph, don't do that, it will cause you issues at some point.
Your code has two problems:
At the following line, you should have provided the parameters for
constructing the Node, which are to and legth.
vector<vector<Node>>(n, vector<Node>(n,0x3fffffff));
// ^^^^^^^^^^^--> here
In Graph, the member n is un-initialized, at the
point, you call the default constructor. That would lead you to have
a garbage value in n and hence the size of the nodes_list would
be undefined.
The fixed code will look like:
struct Node
{
int _to;
int _length;
Node(int to, int length) : _to{ to }, _length{ length } {}
};
class Graph
{
using VecNode = std::vector<Node>; // type alias for convenience
private:
int _n;
std::vector<VecNode> _nodes_list;
public:
Graph()
: _n{ 2 } // initialize _n
, _nodes_list{ _n, VecNode(_n, { 1, 3 }) }
// ^^^^^^-> initialize with the default 'Node(1, 3)'
{}
};
Also some suggestions:
Use member initializer
lists
to initialize the vector, instead of creating and assign to it.
It's not a good idea to name both constructor parameters and the
members with same in Node. At some point, that may lead to
confusions.
I'm trying to access a structure using another structure. From the below program, element is the member of Node. At this line " temp->element *e_temp;", I couldn't link the "element" member of Node to the "elements" structure object.
compile error says "'e_temp' was not declared in this scope". What am I missing?
#include <vector>
#include <cstdlib>
using namespace std;
typedef struct Elements
{
int data;
struct Elements *next;
}elements;
typedef struct Node
{
int sno;
elements *element;
struct Node *next;
}node;
void add(int sno, vector<int> a)
{
node *temp;
temp = new node;
temp->element *e_temp;
e_temp = new elements;
temp->sno = sno;
while(a.size())
{
temp->e_temp->data = a[0];
temp->e_temp = temp->e_temp->next;
a.erase(a.begin());
}
}
int main()
{
vector<int> a{1,2,3};
int sno = 1;
add(sno, a);
return 0;
}
If you're just looking to declare a local you can do auto e_temp = new elements but what i think you want is this for that line temp->element = new elements;
and then follow up with the rest of your code to reference temp's element instead of e_temp.
temp->element->data = a[0];
temp->element = temp->element->next
Also, i'd try to get out the habit of using new and use std::shared_ptr and std::unique_ptr instead.
The correct declaration for e_temp is
elements * e_temp;
but e_temp is not use of any part of your code.
Recently I was working on a project that involved passing arguments by value in C++ and something strange was happening when trying to access the argument fields. The code looked like this:
int main (){
int sizes[] = {2, 3};
Topology top;
top.set_dim(2); // 2D topology
top.set_sizes(sizes); // 2 rows and 3 columns
Architecture arch;
arch.set_topology(top);
}
The Topology class looks like this (it does not have a copy constructor, so I assume it will be generated automatically by the compiler and will be a shallow one, only copying the pointer address, not the data inside):
class Topology {
public:
Topology();
~Topology();
void set_dim(int);
void set_sizes(int*);
int get_dim();
int* get_sizes();
private:
int dim;
int *sizes;
};
Topology::Topology(){
}
Topology::~Topology(){
if (sizes != NULL)
delete sizes;
}
void Topology::set_dim(int dim_){
dim = dim_;
}
void Topology::set_sizes(int *sizes_){
sizes = new int[dim];
for (int i = 0; i < dim; i++){
sizes[i] = sizes_[i];
}
}
int Topology::get_dim(){
return dim;
}
int* Topology::get_sizes(){
return sizes;
}
The Architecture class is the following:
class Architecture {
public:
Architecture();
~Architecture();
void set_topology(Topology top);
private:
Parallelization p;
};
Architecture::Architecture(){
}
Architecture::~Architecture(){
}
Architecture::set_topology(Topology top){
p.set_topology(top);
}
Finally, the Parallelization class:
class Parallelization{
public:
Parallelization();
~Parallelization();
void set_topology(Topology top);
private:
};
Parallelization::Parallelization(){
}
Parallelization::~Parallelization(){
}
void Parallelization::set_topology(Topology top){
int *s = top.get_sizes();
for (int i = 0; i < top.get_dim(); i++){
std::cout << s[i] << " "; // here it prints different numbers, like the vector was never initialized [23144, 352452]
}
}
Shortly, I have a Topology object that gets passed to the Architecture and then to the Parallelization class and there I want to see the internal values from the topology sizes vector. Every time the object is passed by value the implicit copy constructor is called and copies only the dim field and the address of the sizes field, not the whole vector. I wonder why I receive different values, because the vector is still in memory, so it should print the same values.
I mention that if I implement a deep copy-constructor inside the Topology class it works just fine, or if I send the top object by reference.
Am I missing something? What could be the cause of this behavior?
I have a class, whereby one of its elements is of another class, but is an array
class B
{
public:
B() //default
{
element = new A [1]; count = 0;
}
A add(A place)
{
A* newArr;
newArr = new A [count+1];
newArr = element;
newArr[count+1] = place;
delete element;
return newArr[count+1];
}
protected:
int count;
A* element;
};
I am trying to use dynamic arrays, where I when adding the element, I make a new array dynamically, initilzed to the size of the old array plus 1, then copy the elements of the old array to the new array, and then delete the old array. But I am unsure of how to modify the array that's already within the class, if that makes sense (Basically what to return in my add method).
In C++ there's no notion of resizing arrays once declared. Same goes for dynamic arrays, which can't be resized once allocated. You can, however, create a bigger sized array, copy all elements from the older array to the newer one and delete the old one. This is discouraged and would not be performant.
Using std::vector would allow you to add at will and will also keep track of its size, so you don't need count as part of the class.
class B
{
// no need to allocate, do add when required i.e. in B::add
B() : count(), elements() { }
A add(A place)
{
// unnecessarily allocate space again
A *new_elements = new A[count + 1];
// do the expensive copy of all the elements
std::copy(elements + 0, elements + count, new_elements);
// put the new, last element in
new_elements[count + 1] = place;
// delete the old array and put the new one in the member pointer
delete [] elements;
elements = new_elements;
// bunp the counter
++count;
return place; //redundant; since it was already passed in by the caller, there's no use in return the same back
}
protected:
size_t count;
A *elements;
};
The above code perhaps does what you want but is highly discouraged. Use a vector; you code will simply become
class B
{
// no need of a constructor since the default one given by the compiler will do, as vectors will get initialized properly by default
void Add(A place)
{
elements.push_back(place);
// if you need the count
const size_t count = elements.size();
// do stuff with count here
}
protected:
std::vector<A> elements;
};
A more thorough example would be to more closely mimic std::vector:
template<typename T>
class B
{
private: // don't put data under a protected access!
std::size_t _capacity;
std::size_t _size;
T* _elements;
public:
B() : _capacity(0), _size(0), _elements(nullptr) {}
// other methods
void add(const T& t)
{
if (_size >= _capacity) // need to resize the array
{
_capacity++; // you can make this better by increasing by several at a time
T* temp = new T[_capacity];
std::copy(_elements, _elements + _size, temp);
delete [] _elements;
_elements = temp;
}
_elements[_size++] = t;
}
};
I have defined a vector like this in the header file
class entry
{
public:
int key;
int next;
};
std::vector<entry *> TB;
in the cpp file, I wrote:
int s1, val;
s1 = 10; val = 2;
gh = (TB.size() % s1);
However when I want to write something to it, I get segmentation fault
TB[gh]->key = val;
What is the problem with the assignment?
The vector has no elements. Use push_back() or insert() to add elements to the vector:
entry* e = new entry();
e->key = val;
e->next = 0;
TB.push_back(e); // Append to vector.
TB.insert(TB.begin(), e); // Insert at beginning of the vector.
When destroying the vector TB you must iterate over the elements and delete each individually (or use a smart pointer as the element type, such as boost::shared_ptr<entry> or std::unique_ptr<entry>).
You could provide a constructor(s) for entry to make the addition of an entry to TB more concise:
class entry
{
public:
entry(int a_key, int a_next = 0) : key(a_key), next(a_next) {}
int key;
int next;
};
TB.push_back(new entry(val));
TB.insert(TB.begin(), new entry(val));
The TB vector is empty, until you fill it with some pointers.
E.g. TB.resize(100);.
The points in TB should point to valid addresses, i.e. some valid entry instances. E.g. TB[0] = new entry();.
So:
std::vector<entry *> TB(1);
TB[0] = new entry();
TB[0]->key = 42;