C++ persistence of inserting local variable into a std::map by reference - c++

I'm new to C++ and trying to understand a simple example of inserting a list of integers into a map.
#include <iostream>
#include <map>
#include <list>
using namespace std;
map<string, list<int>> m;
void insert(list<int>& list_to_insert)
{
m.insert({"ABC", list_to_insert});
}
void setup()
{
std::list<int> local_list = { 7, 5, 16, 8 };
insert(local_list);
}
int main()
{
setup();
cout << m["ABC"].size(); // PRINTS 4
}
As far as my understanding, local_list is a variable only known to the setup function. When I pass in a reference to the insert function, I expect it to work. However, at the end of setup, I expect local_list to be removed from the stack frame. However, in my main function, when I call size(), I see that it has in fact persisted throughout. I am not sure I understand how local_list gets persisted at the end of setup(). What is exactly happening here?

map<string, list<int>> m;
contains lists, not references to lists.
So your
m.insert({"ABC", list_to_insert});
will create a copy of the passed list.
PS: why-is-using-namespace-std-considered-bad-practice

Related

std::map with structs as values

I have an issue where I need to keep a map of, e.g. vectors, of items, each vector has a corresponding indicator valid for all items for a given key in the map
I guess it could be map of pairs (map<string,pair<vector,bool>>) but that would e very confusing...
So
I wanted to ask you about code like that:
Would this be considered a correct implementation of the problem, is there any potential issue with this? When I add a new key with myMap["KEY"] nothing can ever break because it autoinitializes my struct? Can anything go wrong here?
#include <iostream>
#include <vector>
#include <map>
using namespace std;
struct ListOfItemsWithIndicator
{
bool _indicator;
vector<int> _items;
ListOfItemsWithIndicator(): _indicator(false) {}
};
int main() {
std::map<std::string,ListOfItemsWithIndicator> myMap;
myMap["ONE"]._items.push_back(1);
std::cout << myMap["ONE"]._items[0];
return 0;
}

how to access to a vector in the class from a function that belongs to that class in C++

I am new in C++. I created a cpp and a header file. Here is the header file:
class LISCH{
public:
class lisch_entry{
public:
bool valid;
int link;
int data;
lisch_entry(){
valid = false;
}
};
vector<lisch_entry> data_vec;
public:
LISCH(int);
void insert(int);
};
In cpp file , i need to access that data_vec vector in insert function but i couldn't do it because it's my first time coding in C++. Here is the cpp file:
#include "lisch.h"
#include <iostream>
using namespace std;
LISCH::LISCH(int table_size){
table_size=10;
int x=5;
}
void LISCH::insert(int new_data){
lisch_entry entry;
int add=new_data%11;
if(LISCH.data_vec[add] == NULL) //here i need to acces data_vec
{
}
data_vec.insert(add,new_data); //and also here
}
How can i manage to do that? I need to check if a specific position of the vector is empty or not.
There are quite a few of things wrong with code, probably for lack of planning or formulating the desired effect.
using namespace std; // never do this in real programs.
// Even some tests may fail accidently.
LISCH::LISCH(int table_size){
table_size=10; // those are local variables, why assigning values to them?
int x=5;
}
data_vec is defined as a vector of lisch_entry:
vector<lisch_entry> data_vec;
The you out of blue access element of type lisch_entry with index add. Did you allocate that many elements already? It may not exist at all, the program would crash:
if(LISCH.data_vec[add] == NULL)
An instance lisch_entry cannot be equal, cannot be compared to NULL as far as you had defined it. The check itself looks suspicious, what had you wanted to do?
data_vec.insert(add,new_data);
insert receives an iterator as first parameter. An integer value isn't an iterator. An iterator of add-th element's iterator value is data_vec.begin() + add. It looks like have to check the documentation on std::vector.
You can find shorthanded documentation here: https://en.cppreference.com/w/cpp/container/vector
If you're trying to learn C++ on your own, this may be helpful: https://isocpp.org/faq

calling iterator on list in constructor changes its final value?

I am new to c++ but not to programming, and I am having a very baffling problem. I have class which in its constructor creates a list.
As you can see, I am printing out the final value of the list two different ways, which generally agree with each other: one using list::end, and the other using list::back. Then I call the constructor to this class in my main function, access the list that was created, and try to print the final value. The sample code is given below.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <typeinfo>
#include <list>
#include <algorithm>
#include <queue>
using namespace std;
class Process{
public:
Process(int CB);
int CB;
};
Process::Process(int c){
CB = c;
}
class Event{
public:
Event(Process *process);
Process *process;
};
Event::Event(Process *ps){
process = ps;
}
typedef list<Event> EventList;
class DES{
public:
DES(string originFile);
EventList events;
};
DES::DES(string originFile){
ifstream infile (originFile.c_str());
string str;
while (getline(infile, str)) {
// output the line
//cout << str << endl;
istringstream iss(str);
int AT,TC,CB,IO;
if (!(iss >> AT >> TC>>CB>>IO)) {
cout<<"breaking out of while loop \n";
break;
}
Process p(CB);
Event evt(&p);
this->events.push_back(evt);
}
int cb = this->events.back().process->CB;
EventList::iterator inserter2 = this->events.begin();
EventList::iterator inserter3 = this->events.end();
//inserter3--;
//cout<<"CB after while loop using List<>::end(): " <<inserter3->process->CB<<endl;
//cout<<"CB after while loop using LIST<>::back "<<cb<<endl;
infile.close();
}
int main (int argc, char* argv[]) {
string inputFileName = argv[1];
DES des(argv[1]);
EventList::iterator b = des.events.end();
b--;
cout<<"CB at back of list in main: "<<b->process->CB<<endl;
return 0;
}
So here is where I get confused. The print statement in main should match the output of the print statements in teh constructor, since they are all simply printing the field ->process->CB of the last element of the list. However, for some reason this only works when I uncomment the line //EventList::iterator inserter2 = this->events.begin(); in my constructor. Similarly, if I keep that line and instead comment out the line EventList::iterator inserter3 = this->events.end();, it also doesn't work. Only when I construct an iterator on BOTH the end and beginning of the list does the correct value get printed out in main.
Can anyone shed some light on this odd behavior? I know it must be some simple misunderstanding due to my lack of familiarity with c++, but I have to admit this behavior seems a bit unnatural to me.
EDIT: here is the output with one of the iterators in the constructor commented out:
CB after while loop using List<>::end(): 10
CB after while loop using LIST<>::back 10
CB at back of list in main: 306496
And here is the output with both of the iterators in the constructor:
CB after while loop using List<>::end(): 10
CB after while loop using LIST<>::back 10
CB at back of list in main: 10
-Paul
You're using / storing the address of a local here:
Process p(AT,TC,CB,IO);
Event evt(AT,&p,CREATED,READY);
Once the code block that declares p is exited, any referral to that pointer results in undefined behavior.
Since Process contains a simple int, you could just store copies of Process instead of using pointers.
class Process{
public:
Process(int CB);
int CB;
};
class Event{
public:
Event(const Process& process);
Process process;
};
Event::Event(const Process& ps) : process(ps) {}
Then the first block of code would look like this:
Process p(CB);
Event evt(p);
or simply:
Event evt(Process(CB));
This should at least rid you of the inconsistent results.
If you really do need a pointer, consider smart pointers such as std::unique_ptr or if deemed necessary, std::shared_ptr instead of using raw pointers.

Why only last thread executing?

I need to create console application that counts files in folders. Each folder executes parallel. I get directories paths from .txt file and put them to threads.
I'm using std::thread and boost::filesystem.
It works fine with one directory, but crashes or returns wrong results with many.
What is interesting that last thread always gets correct result, but those before it are wrong.
Here is my code:
DirHandler.h
#include <iostream>
#include <fstream>
#include <string>
#include <thread>
#include <windows.h>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;
class DirHandler{
public:
DirHandler();
void getPaths(ifstream file);
void output();
static void run_thread(pair<string, int> * dir, string cur_path, void *args)
{
DirHandler *prunnable = static_cast<DirHandler*>(args);
prunnable->some_counting(dir, cur_path);
}
private:
vector<thread> threads;
vector<pair<string, int>> paths; // current directory name and files amount
void some_counting(pair<string, int> * dir, string cur_path);
void escape();
};
DirHandler.cpp
void DirHandler::getPaths(ifstream file)
{
// parse pathes and create separate thread for each
string line;
if (file.is_open())
{
while (getline(file, line))
{
cout << line << endl;
// add thread for path
pair<string, int> dir = make_pair(line, 0);
paths.push_back(dir);
threads.push_back(thread(&DirHandler::run_thread, &paths.back(), line, this));
}
for (auto& thr : threads){
thr.join();
}
file.close();
}
}
void DirHandler::some_counting(pair<string, int> * dir, string cur_path){...}
main.cpp
#include <iostream>
#include <windows.h>
#include "DirHandler.h"
int main(int argc, char* argv[])
{
DirHandler dirHandler = DirHandler();
dirHandler.getPaths(ifstream("strings.txt")); //ifstream(argv[1])
dirHandler.output();
return 0;
}
Note : While debugging I've found that all streams before last have id=0 in the end
Also I've read that the problem can be caused by a reference to single object. (In my case it's vector<pair<string, int>> paths)
So my question is how to get few threads work correctly ?
The problem is that you get pointers from the paths vector, and if the vector is resized all previous pointers (and iterators) to elements in the vector will become invalid. Using an invalid pointer leads to undefined behavior which often leads to crashes.
And one common way of causing a vector is to adding new elements to it, exactly what you do in your loop.
One solution is to either pass a reference to the vector and an index of the element to the thread (the index will not change on reallocation). Another solution is to have two loops, one to add all elements to the vector and the second to create the threads.
There are other solutions too, like not passing a pointer to the thread, but instead pass the pair by value. This is actually the solution I recommend.
After checking your code a little, I also see that since you use std::thread you don't need the static member function wrapper at all. Instead you can call the non-static actual thread function directly:
threads.emplace_back(&DirHandler::some_counting, this, paths.back(), line);
[Note the use of this as the second argument, as well as the change to emplace_back for the threads vector]
Well, the most obvious problem is here: threads.push_back(thread(&DirHandler::run_thread, &paths.back(), line, this)); you are using pointer to the object(&paths.back()) which might not be there anymore after any push_back. So this error should be fixed, you can't pass pointer to the vector item unless you can guarantee that it will not reallocate its internal structure.
Besides that and ugly code I don't see anything. But more problems might be lurking in the some_counting method.

Why does this code hang during an insert of stl list

Why this code is hang during insert of stl list?
I have tried copy function also but it also not working.
#include <iostream>
#include <string>
#include <iterator>
#include <list>
#include<vector>
#include<algorithm>
using namespace std;
class a{
list<string> lista;
public:
a()
{
lista.push_back("ele");
lista.push_back("phant");
cout<<"End of Cons"<<endl;
}
list<string> getlist()
{
cout<<"Getting"<<endl;
return lista;
}
};
int main()
{
a A1;
list<string> list1;
list1.insert(list1.end(),A1.getlist().begin(),A1.getlist().end());
//copy(A1.getlist().begin(),A1.getlist().end(),back_inserter(list1));
cout<<"End of Prog"<<endl;
return 0;
}
getlist returns a list by value so list1.insert is using iterators into different lists for its start and end points.
You should change getlist to return a reference to its list rather than a copy of it
list<string>& getlist()
When you are returning a list from a function, using the declaration list<type> getlist(), It will not return the list that you are actually returning(return lista). Instead it makes a temporary copy of that list(lista) an returns that copy. So when you call getlist twice in your insert line, It will return the start and end iterator's of two different lists which creates an ambiguity.
So as #simonc suggested you need to change the declaration so that the copy is not done and an actual list is returned to the calling place.
getList return a copy of list, which has its own memory address in iterator.