How using size_t as a parameter works - c++

So I am making my first attempt in making a hash table and am completely stumped as to what to do for my constructors?
class HashTable {
typedef vector <list<HashNode> > Table;
Table *table; // size of table is stored in the Table data structure
size_t num; // number of entries in the HashTable;
}
this is the class I'm trying to make constructors for and I have been given.
public:
HashTable(); // constructor, initializes table of size 1;
HashTable(size_t num); // constructor, requires size of table as arg
I don't really understand as to what am supposed to do. So first I'm to initialize the size of the table to 1. Which since I'm using a vector, I'm assuming I'm to use the reserve function? So I went ahead and got this:
this->table->resize(num);
which compiled fine and I had no issue with and I think is correct. The second constructor is where I had an issue understanding, mainly due to the use of size_t. By my understanding here is where I set the size of the table to size_t? But what is size_t supposed to be? I think its a data type but why would I set the Hashtable size to a datatype? Unless I'm missing something obvious here I can't see.

Related

C++ vector of custom template class and unclean (?) allocation

I have a quite complex Problem and couldn't find out, where the Problem is. Part of the Problem might be, that i didn't fully understand the data structures. I have the following custom template class, with this member variables:
template <class T>
class Matrix
{
private:
T * *M; /* array of row pointers */
size_t n_rows, /* number of rows */
n_cols; /* number of columns */
size_t row_start, /* first row of submatrix */
col_start, /* first column of submatrix */
origcols; /* refers to original matrix */
bool hasownvalues, /* has matrix own value? */
initialized; /* are matrix values initialed? */
I also made a custom constructor, which makes a 2D array out of a file with tab-separated data:
Matrix(const std::string &filename)
{ do.stuff }
I'm not sure, if it is really important how this exactly works, it quite a bunch of code. if so, i could edit it later, but the constructor works well as long as i declare a single variable for such an object.
My problem occurs when i try to make a bunch of the objects and try to wrap them up in a vector. Lets say i have x different files, each containing data for a matrix. I also have a vector in which the filenames are stored:
std::vector<std::string> filenames{};
for (int idx = 3; idx < argc; idx++)
{
filenames.push_back(argv[idx]);
}
So far this code works and it is mandatory that i keep it unchanged to keep the rest of the program working.
The following is flexible and thats where i have problem:
std::vector<Matrix<T>> coredata; /* initialize the vector for the wrap */
...
for (auto& it : filenames)
{
Matrix<T> M(it); /* call the special constructor*/
coredata.push_back(M); /* add new object to the vector */
}
The first assignment works well, but from the second on it seems that it appends the new Matrix, but also overwrites the old one or at least a part of it. And in the third one i get a segmentation fault when running the program.
Some information of the program around:
the constructor works with space allocated by the "new" command, maybe that could be part of the problem.
the real size of the Matrix object isn't known before run time. (the arrays can be of different size), but i could arrange, that the read data in fact always is of the same size
T is constant within the vector. it can't happen, that M is sometimes Matrix int and sometimes Matrix float
the vector would be embedded in another superclass and the snippet above is part of a constructor of this class, coredata is a member variable.
I'm quite puzzled what the problem exactly is. Maybe some variables don't live long enough. I also thought of assigning just a reference to the address in the vector, but as far as i understand, a vector already stores just a reference, so it seems not that plausible.
I also thought of initializing the vector with a bunch of "0"-matrices and then overwrite them with the constructed objects. But i don't know how to do that and on top of that,
i don't know at compile time how many rows and columns the read Matrices will have.
Maybe a vector isn't a useful solution at all, i also thought of making a plain C-array.
But there i have the problem again, that i have to initialize this array first and can't just append another Matrix-Object to it.

Why is the dynamically allocated array attribute of my class template only able to store one item?

I am trying to expand the functionality of a class template I created. Previously it allowed you to use key-value pairs of any type but only if you knew the size of the arrays at compile time. It looked like this:
template <typename K, typename V, int N>
class KVList {
size_t arraySize;
size_t numberOfElements;
K keys[N];
V values[N];
public:
KVList() : arraySize(N), numberOfElements(0) { }
// More member functions
}
I wanted to be able to use this for a dynamic number of elements decided at run-time, so I changed the code to this:
template <typename K, typename V>
class KVList {
size_t arraySize;
size_t numberOfElements;
K* keys;
V* values;
public:
KVList(size_t size) : numberOfElements(0) {
arraySize = size;
keys = new K[size];
values = new V[size];
}
~KVList() {
delete[] keys;
keys = nullptr;
delete[] values;
values = nullptr;
}
// More member functions
}
The new constructor has one parameter which is the size that will be used for the KVList. It still starts the numberOfElements at 0 because both of these uses would start the KVList empty, but it does set arraySize to the value of the size parameter. Then it dynamically allocated memory for the arrays of keys and values. An added destructor deallocates the memory for these arrays and then sets them to nullptr.
This compiles and runs, but it only stores the first key and first value I try to add to it. There is a member function in both that adds a key-value pair to the arrays. I tested this with the Visual Studio 2015 debugger and noticed it storing the first key-value pair fine, and then it attempts to store the next key-value pair in the next index, but the data goes no where. And the debugger only shows one slot in each array. When I attempt to cout the data I thought I stored at that second index, I get a very small number (float data type was trying to be stored), not the data I was trying to store.
I understand it might be worth using the vectors to accomplish this. However, this is an expansion on an assignment I completed in my C++ class in school and my goal with doing this was to try to get it done, and understand what might cause issues doing it this way, since this is the obvious way to me with the knowledge I have so far.
EDIT: Code used to add a key-value pair:
// Adds a new element to the list if room exists and returns a reference to the current object, does nothing if no room exists
KVList& add(const K& key, const V& value) {
if (numberOfElements < arraySize) {
keys[numberOfElements] = key;
values[numberOfElements] = value;
numberOfElements++;
}
return *this;
}
EDIT: Code that calls add():
// Temp strings for parts of a grade record
string studentNumber, grade;
// Get each part of the grade record
getline(fin, studentNumber, subGradeDelim); // subGradeDelim is a char whose value is ' '
getline(fin, grade, gradeDelim); // gradeDelim is a char whose value is '\n'
// Attempt to parse and store the data from the temp strings
try {
data.add(stoi(studentNumber), stof(grade)); // data is a KVList<size_t, float> attribute
}
catch (...) {
// Temporary safeguard, will implement throwing later
data.add(0u, -1);
}
Code used to test displaying the info:
void Grades::displayGrades(ostream& os) const {
// Just doing first two as test
os << data.value(0) << std::endl;
os << data.value(1);
}
Code in main cpp file used for testing:
Grades grades("w6.dat");
grades.displayGrades(cout);
Contents of w6.dat:
1022342 67.4
1024567 73.5
2031456 79.3
6032144 53.5
1053250 92.1
3026721 86.5
7420134 62.3
9762314 58.7
6521045 34.6
Output:
67.4
-1.9984e+18
The problem (or at least one of them) is with this line from your pastebin:
data = KVList<size_t, float>(records);
This seemingly innocent line is doing a lot. Because data already exists, being default constructed the instance that you entered the body of the Grades constructor, this will do three things:
It will construct a KVList on the right hand side, using its constructor.
It will call the copy assignment operator and assign what we constructed in step 1 to data.
The object on the right hand side gets destructed.
You may be thinking: what copy assignment operator, I never wrote one. Well, the compiler generates it for you automatically. Actually, in C++11, generating a copy assignment operator automatically with an explicit destructor (as you have) is deprecated; but it's still there.
The problem is that the compiler generated copy assignment operator does not work well for you. All your member variables are trivial types: integers and pointers. So they just copied over. This means that after step 2, the class has just been copied over in the most obvious way. That, in turn, means that for a brief instance, there is an object on the left and right, that both have pointers pointing to the same place in memory. When step 3 fires, the right hand object actually goes ahead and deletes the memory. So data is left with pointers pointing to random junk memory. Writing to this random memory is undefined behavior, so your program may do (not necessarily deterministic) strange things.
There are (to be honest) many issues with how your explicit resource managing class is written, too many to be covered here. I think that in Accelerated C+, a really excellent book, it will walk you through these issues, and there is an entire chapter covering every single detail of how to properly write such a class.

Copy values to and from a member of a structure in C++

I have a structure as shown below, which I use for the purpose of sorting a vector while keeping track of the indices.
struct val_order{
int order;
double value;
};
(1). Currently what I do is use a loop to copy values as shown below. So my first question is if there is a faster way to copy values to a member of a structure (not copying an entire structure to another structure)
int n=x.size();
std::vector<val_order> index(n);
for(int i=0;i<x.size();i++){ //<------So using a loop to copy values.
index[i].value=x[i];
index[i].order=i;
}
(2). My second question has to do with copying one member of a structure to an array. I found a post here that discusses using memcpy to accomplish that. But I was unable to make it work (code below). The error message I got was class std::vector<val_order, std::allocator<val_order> > has no member named ‘order’. But I was able to access the values in index.order by iterating over it. So I wonder what is wrong with my code.
int *buf=malloc(sizeof(index[0].order)*n);
int *output=buf;
memcpy(output, index.order, sizeof(index.order));
Question 1
Since you are initializing your n vectors from two different sources (array x and variable i), it would be difficult to avoid a loop. (you could initialize the vectors from index.assign if you had an array of val_order already filled with values, see this link)
Question 2
You want to copy all n order values into a int array, and memcpy seems convenient for that. Unfortunately,
each element of a vector is a val_order structure, so even though you could copy via memcpy that would not only copy the int *order* value but also the double *value* value
furthermore, you are dealing with vector, which internal structure is not a simple array (vector allows operations that are not possible with a regular array) and thus you cannot copy a bunch of vector to a int array by simply giving the address of, say, the first vector element to memcpy.
also, memcpy wouldn't work like you want anyway, but it expects an address - thus you would have to give, e.g., &index[0] ... but again, this is not what you want given the points above
So you would have to make another loop instead, like
int *buf = (int *)malloc(sizeof(int)*n);
int *output = buf;
for (int i=0 ; i<n ; i++) {
output[i] = index[i].order;
}

C++ selection sort - insert method and private variables

I'm in the process of writing a program for selection sort. I just posted something regarding std::vector, however this post is on a different subject.
I was able to compile the program, however it was running into run-time error when insert() was invoked in the main method.
My ArrayS has the code below as a copy constructor and also to initialize nElems to 0 when ArrayS is created.
[ArrayS.cpp]
ArrayS::ArrayS(int max)
{
std::vector<long> a;
nElems = 0;
}
void ArrayS::insert(long value) // put element into array
{
a[nElems] = value; // insert it
nElems++; // increment size
}
[ArrayS.h]
private:
std::vector<long> a;
int nElems;
Now, do I need get/set method in the ArrayS.cpp to manipulate nElems? I'm not sure how in C++ you work with private variables.
Thank you.
Vectors keep track of their size. And to be efficient, a[nElems] will assume that your vector is large enough to accommodate that access.
It looks like you want:
void ArrayS::insert(long value) // put element into array
{
a.push_back(value); // insert it AND increment size
}
It also looks like you can disregard nElems. If you want the vector's size, just call a.size().

C++ Array of Objects

I have an array in a class that should hold some instances of other objects. The header file looks like this:
class Document {
private:
long arraysize;
long count;
Row* rows;
public:
Document();
~Document();
}
Then in the constructor I initialize the array like this:
this->rows = new Row[arraysize];
But for some reason this just sets rows to an instance of Row rather than an array of rows. How would I initialize an array of Row objects?
Both SharpTooth and Wok's answers are correct.
I would add that if you are already struggling at this level you may be better off using a std::vector instead of a built-in array in this case. The vector will handle growing and shrinking transparently.
This should work. One possible "error" would be an incorrect value for arraySize.
However you should better use a std::vector from the standard library for that purpose.
#include <vector>
class Document {
// ...
std::vector<Row> rows;
// ...
};
and in your constructor:
Document::Document() : rows(arraySize) { // ... }
or
Document::Document() { rows.assign(arraySize, Row()); }
If arraySize contains a reasonable value at that point you actually get an array. I guess you trust your debugger and the debugger only shows the 0th element (that's how debuggers treat pointers), so you think there's only one object behind that pointer.
For i in [0;arraysize[, *(this->rows+i) should be an instance of row.
What precisely makes you think that rows is only one element? Make certain that you arraysize isn't 1. If it is, you'll get an array of 1 element. Mind you, you must still call delete [] with an array of size 1.
Also, why is arraysize different than count? Using that terminology, you should be making an array of count elements and arraysize should be equal to sizeof(Row) * count.
Also, you specifically ask "How would I initialize an array of Row objects?". Do you mean allocate? If so, that's how you would do so. If you mean initialize, the default constructor of Row will be called on each element of the array when the array is allocated.