Creating an array of a struct - c++

I am trying to make an array of structs, but I am getting the error no matching function for call to 'Cell::Cell()'.
Cell is the name of my struct. Here is some of my code:
struct Cell{
int number;
Cell(int n){
number = n;
}
};
class MyClass{
public:
int nCells;
void inject(){
std::cout << "Enter number:";
string in;
std::cin >> in;
int amount = in.size()/3;
Cell cells [amount]; // <-- error
int index = 0;
int t = in.size();
while (t >= 3){
cells[index] = new Cell(atoi(in.substr(t-3,3).c_str());
t -= 3;
index++;
}
}
MyClass(int n){
nCells = n;
}
};
Cell cells [amount]; is giving me the error. I am new to classes, but I know how to make arrays of primitive types. int cells [amount]; would work, for instance.
But how am I supposed to make an array of type Cell ?

Cell doesnt have a default constructor (as soon as you specify another constructor the compiler will not create a default constructor anymore). However the definition Cell cells[amount] will automatically default initialize every element.
I think the best way in this particular situation is simply to implement a default constructor:
struct Cell{
int number;
Cell() : number(0)
{
}
Cell(int n) : number(n)
{
}
};
Also notice as amount is not known at compile time, Cell cells[amount] is basically illegal. However some compilers have extensions to allow this. But its better if you heap allocate it:
Cell* cells = new Cell[amount];
Dont forget to destroy it however.

If you know how long the array is, you can use c++11 initialization. This will do :
int main()
{
Cell c[3]{ Cell(1), Cell(2), Cell(3) };
}
By the way this
Cell cells [amount];
is using VLAs, and that is not supported by c++ (only as extension for some compilers).
In c++, much better would be to use std::vector :
#include <vector>
struct Cell{
int number;
Cell(int n){
number = n;
}
};
int main()
{
int n = 5;
std::vector< Cell > c;
for ( int i =0; i < n; ++ i )
{
c.emplace_back( Cell( i ) );
}
}

By doing Cell cells [amount]; you are calling the Cell constructor, but in this case you don't have a default constructor for Cell, so you must use pointers instead, you are using them in the while stuff.
Just change
Cell cells [amount];
for
Cell* cells [amount];

Related

How to do constructor for 2D vector in C++?

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.

Why if passing an object param to another class without having a copy constructor ruins some fields inside the object?

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?

Construct object, where one of its properties depends on another. In C++

Beginner in C++
I have a class, say
class A
{
public:
int N;
double .....
};
But I would like the ..... to define a matrix of size depending on N. In case that changes the approach, it is a non-identical function of N and not just N itself, say N^3+1.
In case that is the approach, I have never written a constructor of an object in C++. Therefore, if this is the approach could you please give some detail. I don't understand how it might work. When the class is instanciated, maybe the property N hasn't been even initialized.
I am not clear how to get a matrix or array (I am still not clear of the basic data types of C++) of size determined in execution.
Edit: The value of N is determined later in the code. It is something like:
A InstanceOfA; //The variable InstanceOfA is declared of type A.
...
Some other stuff happens, e.g. other properties of InstanceOfA are initialized
and some of the functions are used. And then:
...
A.setN(4);
I didn't understand from the answer below. Would I need to do
A InstanceOfA(4);
?
You can use std::vector
class A
{
public:
int N; // you should use int for size
double std::vector<std::vector<double>> matrix; //define the matrix
//initialize it in the constructor
A( int size ):N(size), matrix(size*3+3)// or you can use any expression that evaluates an integral value
{
//you can initialize the values in matrix here
}
};
Note
the expression matrix(size*3+3) initializes the matrix such that, there are size*3+3 rows, the number of columns in each row are not specified yet. You can also specify column sizes in the constructor like
for( int i=0;i< N*3+3; ++i) //for each row
{
matrix[i].resize(N*2);// resize each col to hold N*2 cells,
}
Edit
As per the modification in question, you can then leave the constructor empty (or initialize any other members), and provide a setSize method in class A, which will later initialize the size.
void setSize(int size){
N= size;
matrix.resize( size*3+3);
for( int i=0;i< N*3+3; ++i) //for each row
{
matrix[i].resize(N*2);// resize each col to hold N*2 cells,
}
}
Then you can use it like:
A instanceOfA;
//other code
//
instanceOfA.setSize(N);
You can use an std::vector<std::vector<double>> to capture the matrix. Also, change the type of N to int.
class A
{
public:
int N;
std::vector<std::vector<double>> matrix;
};
Define a constructor and initialize the data in the constructor.
class A
{
public:
A(int n) : N(n)
{
int matrixSize = N*N*N+1;
for (int i = 0; i < matrixSize; ++i )
{
matrix.push_back(std::vecotr<double>(matrixSize));
}
}
double N;
std::vector<std::vector<double>> matrix;
};
One possible way is to do it with a pointer. If you only allocate your array in constructor and its size will not change during the lifetime of your object, that could be done in this way:
class A
{
public:
double N;
double* arr;
A(double aN):N(aN)
{ arr = new double[3*N+1]; // allocate your array in constructor
... // do whatever else you need to initialize your object
}
...
~A() { delete[] arr;} // free it in destructor
...
}
See also the tutorial on Dynamic Memory.
You will then instantiate your class in one of two ways:
A a(aN);
// this object will be automatically destroyed when it gets out of scope, for example at the end of the function where it was created
A* a = new A(aN);
// this object will have to be deleted by yourself when it's no longer needed:
...
delete a;
If you don't know N at the moment when you create your object, you can postpone the allocation :
class A
{
public:
double N;
double* arr = NULL;
A() { ... } // do whatever you need in your constructor
setN(double aN)
{
N = aN;
arr = new double[3*N+1]; // allocate your array
}
...
~A() { if(arr) delete[] arr;} // free your array in destructor if needed
...
}
then you can call your object as:
A a;

c++ correct use of delete after an assignment

I'm a little bit confused on how to use correctly the delete keyword. Here is my scenario:
class Tuple {
public:
Tuple(int columns);
~Tuple();
void set(int i, string d);
string get(int i);
int columnCount();
private:
string *data;
int columns;
};
Tuple::Tuple(int columns) {
this->columns = columns > 0 ? columns : 0;
if (this->columns > 0) {
data = new string[this->columns];
} else {
data = 0;
}
}
Tuple::~Tuple() {
if (columns > 0) {
delete[] data;
}
}
void Tuple::set(int i, string d) {
if (columns > 0 && i > -1 && i < columns) {
data[i] = d;
}
}
class Table {
public:
Table(int columns);
~Table();
void insertTuple(Tuple t);
Tuple getTuple(int i);
int columnCount();
int rowCount();
private:
vector <Tuple> data;
int columns;
int rows;
};
Now, when I call the following code I get a segfault:
Tuple *outTuple;
outTuple = new Tuple(cCount);
for (int i=0; i<cCount; i++) {
tmpStr = string(reinterpret_cast<const char*>(sqlite3_column_text(statement, i)));
outTuple->set(i, tmpStr);
}
(*outTable)->insertTuple(*outTuple);
delete outTuple; //here I get segfault
What is wrong with my code? Is my code not well written? Can I improve it and avoid segfault?
The most likely reason is that the Tuple violates the rule of three. Specifically, you need to define a copy constructor and a copy assignment operator. Otherwise you are probably double-deleting data.
You don't show the constructor and the destructor, but memory management practices employed by Tuple look fragile. Why not use std::vector instead of a pointer?
Dynamically memory allocated variables with pointers, usually have a "container" or "owner".
In this case, the function is the main "container".
"Containtment" or "Ownership" may be transfer, example, from function to other variable, in this case, maybe "outTable".
Does the "outTable" deletes the tuple from memory ?
Are you intended to let "outTable" become the container of the tuple, and let it drop the tuple from memory, instead of the function ?
OR, do you intend that "outTable", only references the tuple, and, let the function drop the tuple from memory.
Cheers.

beginner question about arrays in structs in C++

I would like to create a struct and use it inside an other struct as an array. My problem is that I don't know how big array I would like to allocate, I will only know once I am in a function. I mean I would like to use [] instead of a pre-determined constant, like 10000.
I think if you look at my code it would be self-explanatory. Can you help me how to make this code work? Moreover it would help me a lot if you could tell me what is the name of the topic I am asking about (is it dynamic arrays?) and that where can I find articles/tutorials about this topic.
Here is the code with my broken way of thinking about arrays in structs.
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe keyframes[];
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
my_file.keyframes = new keyframe[my_file.num_keyframes];
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}
Use a std::vector.
struct keyframe_file {
const int num_views;
const int num_keyframes;
std::vector<keyframe> keyframes;
};
int main() {
keyframe_file frame;
frame.keyframes.resize(...);
}
If it suits your purpose, an STL container (std::vector) is easily one of the best options - the less memory management you have to worry about, the better.
In any case, look at the struct definition Nawaz posted above - that's exactly how it should be. Dynamic arrays in C++ are simply pointers. You have, however, allocated the memory properly in your code, but you haven't freed it (so it's leaking). Since you allocated with new [] you will need to
delete [] my_file.keyframes;
in order to free the memory properly.
Resizing is another issue: with a smart implementation, array resizing can be an amortized O(1) operation which is nice. When you resize, it will always take you O(n) since you need to copy all the elements into a new array of different size, but if you do it half as much, it becomes O(1). That is, double the array each time you need to resize. Here is a very quick example
void resize()
{
if(numOfElementsInArray == sizeOfArray)
{
ArrayType * arr = new ArrayType[sizeOfArray*2]; // Allocate a double size array
for(int i=0;i<sizeOfArray;++i)
currentArray[i] = arr[i];
delete [] currentArray; // Free memory in old array
currentArray = arr; // Set the array to our new one
sizeOfArray *= 2; // Double the size
}
}
NOTE: The example above does not take into account space complexity; that said, if you have 5000 elements, and remove all but 5, this method with not shrink it (which is probably what you will want to do for all practical purposes)
Your code appears to be almost correct, except for two things:
keyframes needs to be a keyframe* rather than a keyframe[]
You forgot to delete the memory you allocated
That is incomplete type. In C++, array must be provided with size, and the size must be known at compile time itself.
You're using new, with which you should be using pointer.
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
But std::vector<keyframe> is still a better choice, as #DeadMG already suggested.
By the way, the first two members are const in the struct, that means, they cannot be assigned value, as you're doing in your code. They must be initialized with values you want them to hold. That implies, now with vector, you've to include a constructor, to initialize the struct, as the struct is no more a POD.
struct keyframe_file {
const int num_views; //const member
const int num_keyframes; //const member
std::vector<keyframe> keyframes;
keyframe_file(int nviews, int nkeyframes)
: num_views(nviews), num_keyframes(nkeyframes), keyframes(nkeyframes){}
};
keyframe_file my_file(1,6); //done!
The suggested "Vector" is they safest way to do it.
But if it is only about making your code work (without resizing and stuff) the following should be working:
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file = {1, 6}; // initialization needed bcause of 'const int'
my_file.keyframes = new keyframe[my_file.num_keyframes];
for (int i = 0; i < my_file.num_keyframes; i++)
{
my_file.keyframes[i].a = true;
my_file.keyframes[i].b = 5 + i;
my_file.keyframes[i].c = 9 - i;
}
return 0;
}
somewhere in your code, when you are done using the array you have to call delete [] my_file.keyframes; as already mentioned.
There's a basic rule when using dynamic arrays in c++, especially when using it inside structs or classes, and it's to delete what you no longer need.
If you want to make your struct dynamic, it's easy, just replace the [] with * and the array will become dynamic, but it's not over yet, there is a lot of work.
You have to construct the array and destory it, and destoroying it is possible and useful noly with destructors, like this:
struct keyframe_file
{
const int num_views;
const int num_keyframes;
keyframe* keyframes;
~keyframe_file() // this is the destructor
{
delete[] keyframes;
}
};
Yet even that code isn't going to work at all, since you are assigning values to constants in variable my_file after creating it, it's illegal in c++, you should then use classes instead.
Using classes with dynamic arrays is very easy and interesting and makes your code very good, you don't have to know too much to do that, just learn what is a constructor, an initializer, destructor, private and public and go on with the following code:
#include <iostream>
using namespace std;
struct keyframe
{
bool a;
int b,c;
};
class keyframe_file
{
public:
keyframe_file(int NV, int NKF):num_keyframes(NKF),num_views(NV)
{
keyframes = new keyframe[num_keyframes];
}
~keyframe_file()
{
delete[] keyframes;
}
private:
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file(1,6);
return 0;
}
This code works very well, it allows you to assign value to the constants num_views and num_keyframes for one time when creating the object (variable) my_file.
Remember, you are a C++ programmer, be proud of that, and use classes instead of structs and dynamic arrays instead of static ones.
Hope that's useful.
Use pointers and apply to your structure!
int *p;
p = new int;
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
for (int i = 0; i < my_file.num_keyframes; i++){
my_file.keyframes = new keyframe; //<---
}
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}