Hi I'' trying to make a template for a class to print out values in an array.
#include<iostream>
using namespace std;
template <typename T>
class Array{
public:
Array(T array[], int arraysize){
size=arraysize;
_array=new T[size];
}
~Array(){
delete[] _array;
}
void print(){
for(int i=0; i<size; i++){
cout<<_array[i]<<' ';
}
}
private:
T *_array;
int size;
};
int main(){
int array1[5]={1,2,3,4,5};
Array<int> a(array1,5);
a.print();
float array2[5]={1.012, 2.324, 3.141, 4.221, 5.327};
Array<float> b(array2,5);
b.print();
string array3[]={"Ch1","Ch2","Ch3","Ch4","Ch5"};
Array<string> c(array3,5);
c.print();
return 0;
}
This is the code and I was wondering what's wrong because it would print out random numbers.
The code creates the template's class member _array using new, but does not initialize it to anything, and that's why you get random garbage printed out.
The constructor does receive a parameter array, and an initialized array is passed using that parameter. However, that parameter is completely ignored by the constructor, and nothing is done with it.
Your intent here, obviously, is to copy the contents of the array the template constructor receives, as an argument, into _array. But that code is missing.
The contents of the array parameter will not get copied into _array all by themselves. You have to write the code to do that.
Your constructor:
Array(T array[], int arraysize){
size=arraysize;
_array=new T[size];
}
All you did was to assign the Array's size and allocate memory without actually copying the contents. So all you see some random value for POD types, and default-constructed values for class types.
You should do the copying with std::copy
Array(T array[], int arraysize)
: _array(new T[arraysize]), size(arraysize)
{
std::copy(array, array+arraysize, _array);
}
As you can see, I used member initailizer list; Please remember the Rule of 5. Also, I advise you to use a std::unique_ptr instead.
Related
I don't manage to determine the size of a member array from a parameter passed to the object.
For now I have something like this, which works even if not very convenient: the size of the member array is defined directly in the class header.
main.cpp:
int main()
{
Test foo;
}
class_test.cpp:
Test::Test()
{
}
class_test.h:
class Test
{
public:
Test();
private:
std::array<int,10> myarray; // I define the size here.
};
Now I would like to pass the array size as a parameter when I create the object.
Something like this:
main.cpp:
int main()
{
Test foo(10); // I pass the array size
}
class_test.cpp:
Test::Test(int size): arraysize(size) // I affect the size to a class attribute
{
}
class_test.h:
class Test
{
public:
Test(int size);
private:
int arraysize;
std::array<int,arraysize> myarray; // I use the attribute to determine the member array size
};
I tried a lot of solutions but in the end I always have compile errors.
I saw the other threads on this subject but they didn't allowed me to find how to deal with this configuration.
I could use a vector but in my situation the array's extra performance is very beneficial.
An array's size must be known at compile time (in other words, it's constant).
Either you use std::vector, or you bake that size in the type:
template<int N> // make it a template parameter
class Test
{
public:
Test() {}
private:
std::array<int, N> myarray;
};
Test<10> test; // array of 10 elements.
Personally, I'd recommend vectors, since I doubt the performance difference is that big.
I get this error:
error C2229: class 'GenerateRandNum<int [],int>' has an illegal zero-sized array
In my main, I call my random generator function to input into a empty data set
I call the method in my main like so:
//declare small array
const int smallSize = 20;
int smallArray[smallSize];
// call helper function to put random data in small array
GenerateRandNum <int[], int> genData(smallArray, smallSize);
genData.generate();
Header file
template <class T, class B>
class GenerateRandNum
{
public:
T data;
B size;
GenerateRandNum(T list, B length)
{
data = list;
size = length;
}
void generate();
};
File with method definition
template<class T, class B>
void GenerateRandNum<T, B> ::generate()
{
for (B i = 0; i < size; i++)
{
data[0] = 1 + rand() % size;
}
}
Pointers and arrays are not the same in C/C++. They are two very different things. However, arrays decay into pointers. Most notably in function declarations: The declaration
void foo(int array[7]);
is defined to be equivalent to
void foo(int* array);
That said, all the GenerateRandNum constructor gets, is a int* because that's what T = int [] decays to in the function declaration context. The data member of GenerateRandNum, however, is of type int [] (no decay here), which your compiler assumes to be a zero sized array. Consequently, when you try to assign a pointer to the array, your compiler complains.
You have two options to fix this:
You use an std::vector<> instead, as Marco A. suggests.
You declare your GenerateRandNum class as:
template <class T>
class GenerateRandNum {
public:
T* data;
size_t size;
GenerateRandNum(T* list, size_t length) {
data = list;
size = length;
}
void generate();
};
Note:
I have removed the template parameter for the size type: size_t is guaranteed to be suitable for counting anything in memory, so there is absolutely no point in using anything different. Templating this parameter only obfuscates your code.
There are some problems with your approach:
The first array template parameter can't have its dimension deduced from the argument as n.m. noted, you would need to specify it explicitly:
GenerateRandNum<int[20], int>
There no point in doing
data = list
since in your code sample these are two arrays and you can't assign them directly. You can either copy the memory or specialize your routines/template
You should really consider using a vector of integers, e.g.
template <class T, class B>
class GenerateRandNum
{
public:
T data;
B size;
GenerateRandNum(T list, B length) {
data = list;
size = length;
}
void generate();
};
template<class T, class B>
void GenerateRandNum<T, B> ::generate()
{
srand((unsigned int)time(NULL)); // You should initialize with a seed
for (B i = 0; i < size; i++) {
data[i] = 1 + rand() % size; // I believe you wanted data[i] and not data[0]
}
}
int main(){
//declare small array
const int smallSize = 20;
std::vector<int> smallArray(smallSize);
// call helper function to put random data in small array
GenerateRandNum <std::vector<int>, int> genData(smallArray, smallSize);
genData.generate();
}
Example
I fixed two issues in the code above, take a look at the comments.
When I declare vector to get a class, but cannot access member variable.
Code has more details,
class test{
public :
int num; //member variable
test(int k){ //constructor
num=k;
}
};
int main(){
vector<test *> a[10]; //declare vector
for(int i=0;i<10;i++)
a.push_back(new test(p)); //use constructor initial
for(int i=0;i<10;i++)
cout<<a[i].num<<endl; //THIS STEP ERROR, 'NO MENBER num'
}
I can't find out solution. QAQ~
class test{
public :
int num; //member variable
test(int k){ //constructor
num=k;
}
Why not a struct if all members are public anyway?
Also, that ctor calls for a ctor-init-list, like this, instead:
struct test{
int num;
test(int num) : num(num) {}
};
int main(){
vector<test *> a[10]; //declare vector
Lies in advertising, you are actually defining, and an array of ten vectors.
vector<test*> a; // This is a vector of pointers to test
for(int i=0;i<10;i++)
a.push_back(new test(p)); //use constructor initial
for(int i=0;i<10;i++)
cout<<a[i].num<<endl; //THIS STEP ERROR, 'NO MENBER num'
}
a[i] is of type test*, and pointers do not have members. You wanted to use the arrow-operator ->.
cout<<a[i]->num<<endl;
Last, you forgot to delete all that memory you allocated.
Solutions:
Don't allocate dynamic memory but store test-objects directly.
vector<test> a; // This is a vector of test
for(int i=0;i<10;i++)
a.push_back(test(p)); //use constructor initial
for(int i=0;i<10;i++)
cout<<a[i].num<<endl;
Use smart-pointers (<memory>):
vector<std::unique_ptr<test>> a; // This is a vector of std::unique_ptr<test>
for(int i=0;i<10;i++)
a.push_back(new test(p)); //use constructor initial
for(int i=0;i<10;i++)
cout<<a[i]->num<<endl;
Add all the manual memory-management, but remember all allocations can throw.
Too long and error-prone, won't write it.
You have declared an array of vectors:
std::vector<> a[10];
An array of 10 vectors.
Each slot in the array is a vector of pointers to your test class:
std::vector<Test *> a[10];
So, to access a Test item, you will need to find out which array element to access and where the item is inside the array:
Test p_object = 0;
p_object = a[3].[2]; // The fourth vector, the third slot in the fourth vector.
std::cout << "Test item from 3rd slot in 4th vector: "
<< p_object->num
<< "\n";
I don't think this is what you need or want. The picture that the code shows resembles a 2d matrix. Usually, 2d Matrices are declared as a vector of vectors or a 2d array; not a combination of both.
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;
I'm trying to write a fake vector for my class assignment, and I currently get an error in the member function pushBack.
The compiler doesn't seem to like incrementing the SIZE variable which holds the number of elements in the "vector". Is there something I might need to fix?
Your assistance would be highly appreciated for helping me with this, and any other problems you might happen to find.
/*
Write a simple program that simulates the behavior of vectors
-You should be able to add and remove elements to the vector
-You should be able to access an element directly.
-The vector should be able to hold any data type.
*/
#include <stdio.h>
template <class T, int SIZE>
class Vector
{
#pragma region constructors&destructors
private:
T vec[SIZE];
public:
Vector()
{}
~Vector()
{}
#pragma endregion
template <class T/*, int SIZE*/>
void defineVec(T var)
{
for(int i=0; i<SIZE; i++)
{
vec[i] = var;
}
//printf("All elements of the vector have been defined with %", var)
//What should I do when trying to print a data type or variable
//of an unspecified one along with the '%'?
}
template <class T/*, int SIZE*/>
void pushBack(T var)
{
SIZE ++; //C1205
vec[SIZE - 1] = var;
}
template <class T/*, int SIZE*/>
void popBack()
{
vec[SIZE - 1] = NULL;
SIZE--;
}
//template <class T/*, int SIZE*/>
void showElements()
{
for(int i=0; i<SIZE; i++)
{
printf("%d",vec[i]);
printf("\n");
}
}
};
int main()
{
Vector <int, 5> myints;
myints.pushBack(6);
myints.showElements();
return 0;
}
You're passing SIZE as a template parameter. Inside the definition of a template, a non-type template parameter is basically a constant -- i.e., you can't modify it.
You'll need to define a separate variable to keep track of how much of the storage in your vector-alike is currently being used.