Windows Visual Studio C++ lists of lists - c++

Windows lists
Found the following post somewhat helpful but I'm still struggling.
Creating list of lists in c++
What I require is a list of string lists.
So:
#include <list>
typedef list<std::string, allocator<std::string>>> LISTSTR;
typedef list<LISTSTR, allocator<LISTSTR>> LISTLISTSTR; // uncertain what this is doing?!!?
main()
{
LISTLISTSTR records;
// Add a blank string list to the list
LISTSTR *rowoffields = new LISTSTR();
rowoffields->insert(string("Field1"); // also tried new string("Field1")
records.insert(rowoffields); // also tried *rowoffields
}
But this returns the compile error :
no instance of overloaded function "std::list<_Ty,_Alloc>::insert[with _Ty=std::string, _Alloc=std::allocator<std:string>]" matches the argument list
argument types are (std::string) // or types are (std::string*) if using new string("Test")
object type is: LISTSTR
no instance of overloaded function "std::list<_Ty,_Alloc>::insert[with _Ty=LISTSTR, _Alloc=std::allocator<LISTSTR>]" matches the argument list
argument types are (LISTSTR*) // or types are (LISTSTR) if using *rowoffields
object type is: LISTLISTSTR

Here is one way to go about doing it that is perhaps a bit closer to Python's normal usage. We first declare an array of pointers to a list of strings (type-specified-up-front, not Python-duck-typed (though we could do that with templates). Then we use those pointers in a memory-safe fashion (no leaks) to make new lists. Notice in this specific setup that the total number of lists is fixed at compile-time (and is equal to const int SIZE), and the array of pointers lives on the stack, but the lists the pointers point to are all dynamically allocated on the heap. (You can do this with new and delete, but the newer smart pointers are really the way to go).
#include <list>
#include <memory> //for the smart pointers
#include <iostream>
const int SIZE = 3;
int main() {
//make an array of smart pointers to list of strings:
std::unique_ptr<std::list<std::string>> myLists[SIZE];
//use each smart pointer in the list to make a new list:
for (int i = 0; i < SIZE; i++) {
myLists[i] = std::make_unique<std::list<std::string>>();
}
//load each new list with a single string:
myLists[0]->push_front("Hello");
myLists[1]->push_front("World,");
myLists[2]->push_front("I'm C++!");
//print the results
for (int i = 0; i < SIZE; i++) {
std::cout << myLists[i]->front() << " ";
}
std::cout << std::endl;
return 0;
}
Now if you wanted to be able to add more lists to your list of lists at runtime, you'd have to dynamically allocate the array of pointers to list, rather than do it with static (automatic) allocation as in this example. (Edit: Or, you could set some upper limit, say 100, and then make that the max amount of lists in the application. Probably want to use a std::array to hold that list of pointers, rather than the plain array above, as std::array does bounds checking as with Python).
For the simpler version:
#include <list>
//remove typedefs
int main() { //notice the int!
const int SIZE = 10;
//make array of pointers to list of strings (on stack, fixed size)
std::list<std::string>* myLists[SIZE];
//use pointer to make new list on heap:
myLists[0] = new std::list<std::string>;
//use pointer syntax (instead of . use ->) to call list functions
myLists[0]->push_front("Old style C++");
//more code...
//when finished must remember to free that memory:
delete myLists[0];
//and not leave a dangling pointer:
myLists[0] = nullptr;
return 0;
}

Related

Pointers vs vectors for arrays c++

In the case I am creating an 'array' on stack in c++, is it better to initialise an empty vector with a reserved number of elements and then pass this to a function like foo() as a reference as below. Or is it better to set an array arrb of size nelems, then using a pointer p_arrb to the address of the first element increment the pointer and assign some value?
#include <iostream>
#include <vector>
void foo(std::vector<int>& arr){
int nelems = arr.capacity();
for (int i = 0; i < nelems; i++){
arr[i] = i;
}
}
int main()
{
int nelems;
std::cout << "Type a number: "; // Type a number and press enter
std::cin >> nelems;
std::vector<int> arr;
arr.reserve(nelems); // Init std lib vector
foo(arr);
int arrb[nelems];
int* p_arrb = &(arrb[0]); // pointer to arrb
for (int i = 0; i < nelems; i ++){
*(p_arrb++) = i; // populate using pointer
}
p_arrb -= nelems; // decrement pointer
return 0;
}
It seems people prefer the use of vector as it is standardised and easier to read? Apart from that, is there any performance benefit to using vector instead of a basic pointer in this case where I do not need to change the size of my vector/array at any point in the code?
What you should use depends on the exact goal you have. In general the best approach is to avoid using "raw arrays" (both dynamic and static) wherever possible.
If you need dynamic array, use std::vector. If you need static array, use std::array.
You can't use the arrb variant because the size of an array must be a compile-time constant in C++, but you are trying to use a runtime size here.
If your compiler is compiling this, then it is doing so only because it supports these so-called variable-length arrays as a non-standard extension. Other compilers will not support them or have differing degree of support or behavior. These arrays are optionally-supported in C, but even there they are probably not worth the trouble they cause.
There is no way to allocate a runtime-dependent amount of memory on the stack in C++ (except if you misuse recursive function calls to simulate it).
So yes, you should use the vector approach. But as discussed in the comments under the question, what you are doing is wrong and causes undefined behavior. You need to either reserve memory and then emplace_back/push_back elements into the vector or you need to resize the vector to the expected size and then you may index it directly. Indexing a vector outside the the range of elements already created in it causes undefined behavior.

Appending struct by reference to an array in C++

How can I implement a function in C++ that appends a struct instance to an array by reference? So that after appending a struct stored in a variable to the array, this variable can be used further to change the instance of array.
pseudocode:
struct St{
int x
}
St* arr;
St a = {0};
append a to arr;
a.x = 1;
//expecting arr[0].x = 1
Here is the C++ code with the film example (see comments describing the problem):
struct Film{
int id;
char* name;
};
void add_film(Film *&films, int &size, Film &film){
if (size == 0)
films = new Film[1];
else
{
Film *tmp = new Film[size + 1];
for (int i = 0; i < size; ++i)
{
tmp[i] = films[i];
}
delete[]films;
films = tmp;
}
films[size] = film;
film = films[size]; //how to reassign passed film object to a new object in array?
size++;
}
int main(){
Film *films = nullptr;
int size = 0;
Film film = {1, "Name1"};
add_film(films, size, film);
film.name = "Name2";
std::cout << films[0].name; //output: "Name1", expected: "Name2"
}
Appending struct by reference to an array in C++
There are two problems with this:
There cannot be arrays of references in C++.
There is no way to append to an array. The size of an array is a constant. There is no way to add or remove elements.
An issue with your attempted solution is that you have an array of Films, and not an array of references. This isn't very surprising, as problem 1 described above states there are no such thing as arrays of references. The solution is simple however: Use pointers instead of references. Technically, you could use a reference wrapper instead, but a pointer is often simpler.
You've basically figured out the solution to 2. already. What you're doing is creating a new array, copying the old elements from the old array into the new one, and destroying the old array. That's a good approach in general, but there are a number of problems with this trivial implementation:
Bare owning pointers are unsafe and hard to use.
Reallocating and copying the entire array on every append is very expensive.
Former can be solved by using the RAII idiom, and latter can be solved by separating the storage of the objects from the creation of the objects, and by growing the storage by a constant factor i.e. geometrically. There is no need to implement such RAII container though, since the standard library has you covered. It's called std::vector.
In conclusion: You can use std::vector<Film*>.

C++ Function Alters Value of Passed Parameter

I have a simple swapping function to take an integer array, and return a new array with swapped values.
int* Node::dataSwap(int *data, int n_index, int swap_index){
printDatt(data);
int *path = data;
int swapped = data[n_index];
int to_swap = data[swap_index];
path[n_index] = to_swap;
path[swap_index] = swapped;
printDatt(data);
return path;
}
However, the reference to the original data is being altered by this function. The output looks something like this (printing the should be the same data to console).
0, 1, 2
3, 4, 5
6, 7, 8
0, 1, 2
3, 4, 8
6, 7, 5
Why is "data" being changed when I am not changing it? Is "path" a reference to the actual mem addr of "data"?
The type of the argument data and the local variable path is int *. You can read this as "pointer to int".
A pointer is a variable holding a memory address. Nothing more, nothing less. Since you set path = data, those two pointers are equal.
In your mind, data is an array. But that's not what the function dataSwap is seeing. To the function dataSwap, its argument data is just a pointer to an int. This int is the first element of your array. You accessed elements of the array using data[n_index]; but that's just a synonym for *(data + n_index).
How to remedy to your problem?
The C way: malloc and memcpy
Since you want to return a new array, you should return a new array. To do this, you should allocate a new region of memory with malloc, and then copy the values of the original array to the new region of memory, using memcpy.
Note that it is impossible to do this using only the current arguments of the function, since none of those arguments indicate the size of the array:
data is a pointer to the first element of the array;
n_index is the index of one of the elements in the array;
swap_index is the index of another element in the array.*
So you should add a fourth element to the function, int size, to specify how many elements are in the array. You can use size as argument to malloc and memcpy, or to write a for loop iterating over the elements of the array.
New problem arising: if you call malloc to allocate new memory, then the user will have to call free to free the memory at some point.
C++ has the cool keyword new whose syntax is somewhat lighter than the syntax of malloc. But this doesn't solve the main problem; if you allocate new memory with the keyword new, then the user will have to free the memory with the keyword delete at some point.
Urgh, so much burden!
But this was the C way. A good rule of thumb in C++ is: never handle arrays manually. The standard library has std::vector for that. There are situations where using new might be the best solution; but in most simple cases, it isn't.
The C++ way: std::vector
Using the class std::vector from the standard library, your code becomes:
#include <vector>
std::vector<int> Node::dataSwap(std::vector<int> data, int n_index, int swap_index)
{
std::vector<int> new_data = data;
int swapped = data[n_index];
int to_swap = data[swap_index];
new_data[n_index] = to_swap;
new_data[swap_index] = swapped;
return (new_data);
}
No malloc, no new, no free and no delete. The class std::vector handles all that internally. You don't need to manually copy the data either; the initialisation new_data = data calls the copy constructor of class std::vector and does that for you.
Avoid using new as much as you can; use a class that handles all the memory internally, like you would expect it in a higher-level language.
Or, even simpler:
The C++ way: std::vector and std::swap
#include <vector>
#include <algorithm>
std::vector<int> Node::dataSwap(std::vector<int> data, int n_index, int swap_index)
{
std::vector<int> new_data = data;
std::swap(new_data[n_index], new_data[swap_index]);
return (new_data);
}
Is "path" a reference to the actual mem addr of "data"?
Yes! In order to create a new array that is a copy of the passed data (only with one pair of values swapped over), then your function would need to create the new array (that is, allocate data for it), copy the passed data into it, then perform the swap. The function would then return the address of that new data, which should be freed later on, when it is no longer needed.
However, in order to do this, you would need to also pass the size of the data array to the function.
One way to do this, using 'old-style' C++, is with the new operator. With the added 'size' parameter, your function would look something like this:
int* Node::dataSwap(int *data, int n_index, int swap_index, int data_size)
{
printDatt(data);
int *path = new int[data_size]; // Create new array...
for (int i = 0; i < data_size; ++i) path[i] = data[i]; // ... and copy data
int swapped = data[n_index];
int to_swap = data[swap_index];
path[n_index] = to_swap;
path[swap_index] = swapped;
printDatt(data);
return path; // At some point later on, your CALLING code would "delete[] path"
}
You are changing the memory at which the pointer path point and that is data. I think try to understand better how the pointers works will help you. :)
Then you can use the swap function from the std library:
std::swap(data[n_index], data[swap_index]);
It will make your code nicer.

How can I make my dynamic array or vector operate at a similar speed to a standard array? C++

I'm still quite inexperienced in C++ and i'm trying to write sum code to add numbers precisely. This is a dll plugin for some finite difference software and the code is called several million times during a run. I want to write a function where any number of arguments can be passed in and the sum will be returned. My code looks like:
#include <cstdarg>
double SumFunction(int numArgs, ...){ // this allows me to pass any number
// of arguments to my function.
va_list args;
va_start(args,numArgs); //necessary prerequisites for using cstdarg
double myarray[10];
for (int i = 0; i < numArgs; i++) {
myarray[i] = va_arg(args,double);
} // I imagine this is sloppy code; however i cannot create
// myarray{numArgs] because numArgs is not a const int.
sum(myarray); // The actual method of addition is not relevant here, but
//for more complicated methods, I need to put the summation
// terms in a list.
vector<double> vec(numArgs); // instead, place all values in a vector
for (int i = 0; i < numArgs; i++) {
vec.at(i) = va_arg(args,double);
}
sum(vec); //This would be passed by reference, of course. The function sum
// doesn't actually exist, it would all be contained within the
// current function. This is method is twice as slow as placing
//all the values in the static array.
double *vec;
vec = new double[numArgs];
for (int i = 0; i < (numArgs); i++) {
vec[i] = va_arg(args,double);
}
sum(vec); // Again half of the speed of using a standard array and
// increasing in magnitude for every extra dynamic array!
delete[] vec;
va_end(args);
}
So the problem I have is that using an oversized static array is sloppy programming, but using either a vector or a dynamic array slows the program down considerably. So I really don't know what to do. Can anyone help, please?
One way to speed the code up (at the cost of making it more complicated) is to reuse a dynamic array or vector between calls, then you will avoid incurring the overhead of memory allocation and deallocation each time you call the function.
For example declare these variables outside your function either as global variables or as member variables inside some class. I'll just make them globals for ease of explanation:
double* sumArray = NULL;
int sumArraySize = 0;
In your SumFunction, check if the array exists and if not allocate it, and resize if necessary:
double SumFunction(int numArgs, ...){ // this allows me to pass any number
// of arguments to my function.
va_list args;
va_start(args,numArgs); //necessary prerequisites for using cstdarg
// if the array has already been allocated, check if it is large enough and delete if not:
if((sumArray != NULL) && (numArgs > sumArraySize))
{
delete[] sumArray;
sumArray = NULL;
}
// allocate the array, but only if necessary:
if(sumArray == NULL)
{
sumArray = new double[numArgs];
sumArraySize = numArgs;
}
double *vec = sumArray; // set to your array, reusable between calls
for (int i = 0; i < (numArgs); i++) {
vec[i] = va_arg(args,double);
}
sum(vec, numArgs); // you will need to pass the array size
va_end(args);
// note no array deallocation
}
The catch is that you need to remember to deallocate the array at some point by calling a function similar to this (like I said, you pay for speed with extra complexity):
void freeSumArray()
{
if(sumArray != NULL)
{
delete[] sumArray;
sumArray = NULL;
sumArraySize = 0;
}
}
You can take a similar (and simpler/cleaner) approach with a vector, allocate it the first time if it doesn't already exist, or call resize() on it with numArgs if it does.
When using a std::vector the optimizer must consider that relocation is possible and this introduces an extra indirection.
In other words the code for
v[index] += value;
where v is for example a std::vector<int> is expanded to
int *p = v._begin + index;
*p += value;
i.e. from vector you need first to get the field _begin (that contains where the content starts in memory), then apply the index, and then dereference to get the value and mutate it.
If the code performing the computation on the elements of the vector in a loop calls any unknown non-inlined code, the optimizer is forced to assume that unknown code may mutate the _begin field of the vector and this will require doing the two-steps indirection for each element.
(NOTE: that the vector is passed with a cost std::vector<T>& reference is totally irrelevant: a const reference doesn't mean that the vector is const but simply puts a limitation on what operations are permitted using that reference; external code could have a non-const reference to access the vector and constness can also be legally casted away... constness of references is basically ignored by the optimizer).
One way to remove this extra lookup (if you know that the vector is not being resized during the computation) is to cache this address in a local and use that instead of the vector operator [] to access the element:
int *p = &v[0];
for (int i=0,n=v.size(); i<n; i++) {
/// use p[i] instead of v[i]
}
This will generate code that is almost as efficient as a static array because, given that the address of p is not published, nothing in the body of the loop can change it and the value p can be assumed constant (something that cannot be done for v._begin as the optimizer cannot know if someone else knows the address of _begin).
I'm saying "almost" because a static array only requires indexing, while using a dynamically allocated area requires "base + indexing" access; most CPUs however provide this kind of memory access at no extra cost. Moreover if you're processing elements in sequence the indexing addressing becomes just a sequential memory access but only if you can assume the start address constant (i.e. not in the case of std::vector<T>::operator[]).
Assuming that the "max storage ever needed" is in the order of 10-50, I'd say using a local array is perfectly fine.
Using vector<T> will use 3 * sizeof(*T) (at least) to track the contents of the vector. So if we compare that to an array of double arr[10];, then that's 7 elements more on the stack of equal size (or 8.5 in 32-bit build). But you also need a call to new, which takes a size argument. So that takes up AT LEAST one, more likely 2-3 elements of stackspace, and the implementation of new is quite possibly not straightforward, so further calls are needed, which take up further stack-space.
If you "don't know" the number of elements, and need to cope with quite large numbers of elements, then using a hybrid solution, where you have a small stack-based local array, and if numargs > small_size use vector, and then pass vec.data() to the function sum.

How to use a vector of pointers to a structure in c++?

I have an assignment that is due about a week from now. It is about making a letter counter (cases don't matter) of text file in the directory the source file is. Then the output of the letters should be, first, according to the letter with highest number of occurrences of it, and, second, if there are letters with the same number of occurrences, then sorting will be according to the alphabetical order. The assignment page is here: http://www.cs.sfu.ca/CourseCentral/135/tjd/a1.html. I already did a program that has the same output (here it is: https://drive.google.com/file/d/0BxuBN4fpoq5LNHIwR2U2elVkdVE/view?usp=sharing). The thing is, as what you can see from the assignment page, is that my proffisor is insisting that we use a vector, Freq_table, that has pointers to a structure, char_count. I tried to do simple code to add elements to the vector, like this:
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <vector>
using namespace std;
struct char_count {
char c;
int count;
};
typedef vector<char_count*> Freq_table;
int main () {
char_count A_count = {'A', 0};
Freq_table.push_back (A_count);
}
But the compiler always gives this message:
error: expected unqualified-id before '.' token
Freq_table.push_back (A_count);
I can't seem to solve this error. All I need for now is to know what is the syntax of adding elements to a vector that has pointers to a structure.
Regards.
What you are doing is wrong, you are doing something like
int.push_back(A_count);
Furthermore, you tell your vector that you want to store a pointer to a char_count-variable, but you store the variable itself, therefore resulting in another error.
Before you can push values into a vector, you have to declare it. A possible (untested) solution would be
Freq_table newTable;
newTable.push_back(&A_count);
You've declared Freq_table as a type, not an instance, so change:
typedef vector<char_count*> Freq_table;
to:
vector<char_count*> Freq_table;
To add to the table, you have to pass the address of a char_count instance. One way is:
char_count* A_count = new char_count; // allocate a new instance...returns the address.
A_count->c = 'A';
A_count->count = 0;
Freq_table.push_back(A_count);
Don't forget you will have to delete the instances in the vector if allocated with new or you will have memory leaks.
The only redeeming part of that assignment is that you aren't actually required to use dynamic memory. You can use the vector of pointers for only the one purpose it is reasonably well-suited, namely for getting the letters sorted by descending frequency.
The pointers in the vector will be non-owning pointers. It is appropriate to use a raw pointer for non-owning pointers, since that can't cause a memory leak.
Something like this:
int main(void)
{
char_count dictionary_order[26];
for( int i = 0; i < 26; ++i ) dictionary_order[i] = {'A'+i, 0};
/* read the input, count letters.
Notice that the matching letter is always at index ch-'A' */
Freq_table frequency_order;
for (auto& item : dictionary_order) frequency_order.push_back(&item);
sort(frequency_count.begin(),
frequency_count.end(),
[](char_count* a, char_count* b) -> bool
{
return (a->count == b->count)? (a->c < b->c) : (a->count > b->count);
}
);
/* print them out */
}
No dynamic allocation, therefore no leaks. And because C++ destroys local variables in the opposite order of declaration, the pointed-to objects will exist longer than the pointers themselves do.
If you needed to accommodate a variable number of items, you could have a vector<char_count> that manages the memory, and store pointers to those in your mandated vector of pointers. Of course, pointers become invalid if the vector is resized, so you'd build the entire "real" vector before starting to fill the pointer vector.