I am having issues with the following piece of code while using threads.
I read on the Microsoft site that appending to the concurrent_vector does not mess with iterators, so I did not provide and mutex for the duration of the find_if operation.
So the error I am receiving is an "Access violation"
I have 6 threads running concurrently. Should I wrap this in a mutex? Does it need one. I'm fairly new to C++.
std::stringstream key;
key << "SearchString " << ID << ", " << "Options" << ", " << Date;
auto &it = std::find_if(
m_spList.begin(), m_spList.end(),
[&key] (std::unique_ptr<IBaseObject>const &bo){
return bo->ID() == key.str();
}
);
if (it != m_spList.end()) {
while (it != m_spList.end()) {
ReplacePartResult* rpr = dynamic_cast<ReplacePartResult*>(it->get());
if (rpr) {
if (rpr->ReplaceItem) {
replaceBOMID = rpr->BOMID > 0 ? rpr->BOMID : 0;
if (_parentPart) {
_parentPart->TemplateBomID = rpr->BOMID;
_parentPart->Name = rpr->Name;
_parentPart->Description = rpr->Description;
}
}
}
it = std::find_if(
++it, m_spList.end(),
[&key](std::unique_ptr<IBaseObject>const &bo){
return bo->ID() == key.str();
}
);
}
}
Not 100% why, but i re-factored the find_if into a new function and explicitly defined my iterator type and it seems to be behaving. Maybe sening the stringstream into the lambda was the issue?
concurrency::concurrent_vector<std::unique_ptr<IBaseObject>>::iterator IBaseObject_FindKey(concurrency::concurrent_vector<std::unique_ptr<IBaseObject>>& mv, std::string const& _key)
{
return std::find_if(std::begin(mv), std::end(mv), [&_key](std::unique_ptr<IBaseObject>const &bo){return bo->ID() == _key; });
}
Related
Need a bit of help from you.
I am writing an application for c++ having the use of queue STL container in my code.
While accessing the front() element of that queue, I am encountering a "deque iterator not dereferencable" error. This specific error is coming in debug mode only.
The code is below.
// haraldMsgDb is a queue of strings declared in header file
// std::queue <std::string> haraldMsgDb;
void handle_message(Message& message)
{
std::string dataString = "\"" + std::string(message.getName()) + "\":" + std::string("#") + "\"" + std::string(message.getTime().toString()) + "\"" + std::string(":") + "\"" + std::string(message.getData()) + "\"";
/* pushing data in queue here*/
App::Instance->haraldMsgDb.push(dataString);
}
/*fetching the queue data in this function*/
void SendData()
{
/*Some stuff*/
while (1)
{
while (!TimeSeriesApp::TimeSeriesAppInstance->haraldMsgDb.empty())
{
if (data.length() < 3000)
{
data += App::Instance->haraldMsgDb.front(); // ---->>> getting the "deque iterator not dereferencable" error here, somtimes the error comes in below line as well
std::string key = App::Instance->haraldMsgDb.front().substr(0, App::Instance->haraldMsgDb.front().find("#"));
std::string value = App::Instance->haraldMsgDb.front().substr(App::Instance->haraldMsgDb.front().find("#") + 1, std::string::npos);
App::Instance->haraldMsgDb.pop();
if (jsonMap.find(key) != jsonMap.end())
jsonMap[key] = jsonMap[key] + "," + value;
else
jsonMap.insert(std::make_pair(key, value));
}
else
{
if (ret == MOSQ_ERR_SUCCESS)
{
str = "{";
for (auto itr = jsonMap.begin(); itr != jsonMap.end(); ++itr) {
str += itr->first + "\n" + "\t\t{" + itr->second + "},\n";
}
str = str.substr(0, str.length() - 2);
str += "}";
}
LOGMESSAGE("data..." << str << std::endl);
LOGMESSAGE("length " << str.length() << std::endl);
/*Some stuff*/
}
}
}
}
int main()
{
handle_incoming_message();
sendData();
return 0;
}
The error is coming in line below while accessing the front element:
data += App::Instance->haraldMsgDb.front();
As I am popping the data from the queue, hence I am checking if the queue is not empty before accessing the front() of queue. but still getting the error.
When I am debugging thoroughly, the error is coming in deque file of Visual Studio:
reference operator*() const
{ // return designated object
const auto _Mycont = static_cast<const _Mydeque *>(this->_Getcont());
#if _ITERATOR_DEBUG_LEVEL == 2
if (_Mycont == 0
|| this->_Myoff < _Mycont->_Myoff
|| _Mycont->_Myoff + _Mycont->_Mysize <= this->_Myoff)
{ // report error
_DEBUG_ERROR("deque iterator not dereferencable");
}
Here, _Mycont is getting null/zero, which is upfront throwing this exception. Could anyone let me know why I am getting this error?
i'm new to C++. My program is a quiz game which user can choose category and level for the questions. At first, i use the struct data type
struct QuestionInfo
{
string category;
string level;
string question;
string answer;
};
then
vector<QuestionInfo> vec;
The idea of this part is to store the info of the question include (category, level, question and answer) to each element.
Then after building menu and the output questions UI, i go to the filters
void category_filter()
{
for (unsigned int i = 0; i < vec.size(); i ++)
{
if (category_choice != vec[i].category)
vec.erase(vec.begin() + i );
}
}
Void level_filter()
{
for (unsigned int i = 0; i < vec.size(); i ++)
{
if (level_choice != vec[i].level)
vec.erase(vec.begin() + i );
}
}
So the idea of the filters is to delete the elements which not contain the matched category and level. But the output questions did not match with the category and the level i had choose before. I'm not sure what I'm doing wrong.
Let me explain you the problem with my example. Suppose you have a vector of 10 elements, valid indexes are 0 till 9 elements. You have to erase 5th element i == 4. You erase it, then 6th element with index 5 moves to place of 5th elements with index 4. After that you increase i in for, it becomes 5. Thus you skip previous 6th element, that is now 5th with index 4.
You may fix your code like below, moving i ++ to the condition.
for (unsigned int i = 0; i < vec.size(); ) {
if (category_choice != vec[i].category)
vec.erase(vec.begin() + i );
else
i ++;
}
The preferable solution in C++ way is demonstrated by #Jonathan.
You're getting tripped up by not accounting for the indexing shift that occurs when you erase an element. I personally would rely on remove_if and erase with a lambda to accomplish this:
vec.erase(remove_if(begin(vec), end(vec), [&](const auto& i) { return category_choice != i.category; }, end(vec));
vec.erase(remove_if(begin(vec), end(vec), [&](const auto& i) { return level_choice != i.level; }, end(vec));
Alternatively you might consider combining them for a bit of speed improvement:
vec.erase(remove_if(begin(vec), end(vec), [&](const auto& i) { return category_choice != i.category || level_choice != i.level; }, end(vec));
You might want to remove_if + erase:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main()
{
struct QuestionInfo
{
std::string category;
std::string level;
std::string question;
std::string answer;
QuestionInfo(std::string category, std::string level, std::string question, std::string answer) :
category(category), level(level), question(question), answer(answer) {}
};
std::vector<QuestionInfo> vec;
std::string category_choice = "cat1";
std::string level_choice = "lev1";
vec.push_back(QuestionInfo("cat1", "lev1", "q1", "a1"));
vec.push_back(QuestionInfo("cat1", "lev2", "q2", "a2"));
vec.push_back(QuestionInfo("cat2", "lev1", "q3", "a3"));
vec.push_back(QuestionInfo("cat2", "lev2", "q4", "a4"));
std::cout << "\nNot filered" << std::endl;
for (auto const &info : vec)
std::cout << "Category:" << info.category << " Level:" << info.level << std::endl;
auto filter_category = std::remove_if(vec.begin(), vec.end(), [&](auto const &info) {return category_choice != info.category; });
vec.erase(filter_category, vec.end());
std::cout << "\nFilered by category" << std::endl;
for (auto const &info : vec)
std::cout << "Category:" << info.category << " Level:" << info.level << std::endl;
auto filter_level = std::remove_if(vec.begin(), vec.end(), [&](auto const &info) {return level_choice != info.level; });
vec.erase(filter_level, vec.end());
std::cout << "\nFiltered by level" << std::endl;
for (auto const &info : vec)
std::cout << "Category:" << info.category << " Level:" << info.level << std::endl;
system("pause");
return 0;
}
As mentioned by others, the remove_if + erase is a standard and expressive way to achieve what you want. But you may also consider non-destructive filtering with a copy_if into a new container, or even without using any additional storage with Boost.Range adaptor boost::adaptors::filtered or boost::filter_iterator. Look here for examples.
I want to convert my for loop into a find_if lambda but I Always get the same result vector iterator not dereferncable.
void SearchObjectDescription(std::vector<std::string>& input, Player & player)
{
//--local variable
bool found = false;
//std::find_if
std::vector<std::string>::iterator i = std::find_if(input.begin(), input.end(),[&](Player player)
{
if ((player.InInventory((*i)) ) == true)
{
std::cout << (player.GetInventory().ItemByName((*i))).ExamineObject() << std::endl;
return true;
}
else
{
std::cout << "Object not in invetory!" << std::endl;
return false;
}
});
//original for loop
//for (std::vector<std::string>::iterator i = input.begin()+1; i != input.end(); i++)
//{
// if (player.InInventory((*i))== true)
// {
// std::cout << (player.GetInventory().ItemByName((*i))).ExamineObject() << std::endl;
// found = true;
// break;
// }
//}
//if (found ==false)
//{
// std::cout << "Object not in invetory!" << std::endl;
//}
}
Can some one help me please?
You are thinking about the lambda wrongly. The std::find_if function takes, as it's third argument, a lambda that takes an element of the vector, and return if it's the element you searched for.
The purpose of the lambda is to take an element and tell if it's the right one.
Yet, your lambda don't receive an element of your vector of string, but takes a player as parameter. But you obviously don't have a list of player, you have a list of string. Why should the element to check should be a Player?
Instead, capture your player variable and receive the element to check. It would look like this:
void SearchObjectDescription(std::vector<std::string>& input, Player & player)
{
auto i = std::find_if(input.begin(), input.end(),[&](const std::string& item)
{
// item is equal to the current element being checked
// player is captured by reference because of [&]
// if the item `item` is in inventory, return true.
return player.InInventory(item);
});
if (i != input.end()) {
// if it's not equal to the end, *i is the found item.
}
}
Note that in C++14, you can receive auto&& in your lambda, and it will be deduced to string&:
std::find_if(input.begin(), input.end(), [&](auto&& item)
{
// type of item is std::string&
// ...
});
You cannot use the i iterator inside of your lambda, because it is not initialized until after std::find_if() exits. You need to use the input parameter of the lambda instead, which will be a std::string from the vector, not a Player object.
Also, you are not checking the return value of std::find_if() to make sure you have a valid iterator before dereferencing it.
You did not translate your for loop to a lambda-based std::find_if() correctly. Try this instead:
void SearchObjectDescription(std::vector<std::string>& input, Player & player)
{
auto i = std::find_if(input.begin()+1, input.end(),
[&](const std::string &s) { return player.InInventory(s); });
if (i != input.end())
{
std::cout << (player.GetInventory().ItemByName(*i)).ExamineObject() << std::endl;
}
else
{
std::cout << "Object not in inventory!" << std::endl;
}
}
I need to get the smallest element in a std::map. I'm aware that there is plenty of documentation available; however, I can't seem to get any to work.
I have two maps, bid and ask, both of which are properties of the Book class. Each is a map of queues. Each of these queues hold Order objects (which have various properties like price, volume, etc.). I have a member function update which obtains the best bid, best ask, and the spread:
void update(void)
{
unsigned long long highest_bid, lowest_ask = 0;
for (std::map<unsigned long long, queue<Order>>::iterator it = this->bid.begin(); it != this->bid.end(); ++it)
{
highest_bid = it->first;
}
// best ask code here
this->bestBid = highest_bid;
this->bestAsk = lowest_ask;
this->spread = labs(this->bestAsk - this->bestBid);
}
Where the ask code is, I've tried the following:
lowest_ask = this->ask.begin()->first;
This compiles, but when I debug it throws an assertion failure (which I've read up on other questions here and can't seem to understand):
Expression: map/set iterator not dereferencable
I've tried reverse iteration:
for(std::map<unsigned long long, queue<Order>>::reverse_iterator rit = this->ask.rbegin(); rit != this->ask.rend(); ++rit)
{
lowest_ask = rit->first;
}
Which compiles and debugs fine, but lowest_ask is always 0, which is wrong. When I step through it in the debugger it doesn't stop until it reaches zero.
I've tried swapping the iterators around:
for(std::map<unsigned long long, queue<Order>>::reverse_iterator rit = this->ask.rend(); rit != this->ask.rbegin(); ++rit)
{
lowest_ask = rit->first;
}
This compiled fine, but once again threw the debug assertion failure.
I could continue on and on on what I've tried, but this question is already over-complicated. I just don't understand why I can't just do what I did at the start (lowest_ask = this->ask.begin()->first).
Thank you very much in advance.
Iterating through the map and always assigning the same variable seems like needlessly hard work.
If you need to access the first item in the map (or the last item in the map) then begin() (or rbegin()) is all you need.
std::map <int, int> themap;
themap[4] = 1;
themap[2] = 2;
themap[1] = 3;
themap[6] = 4;
themap[5] = 5;
themap[7] = 6;
if (!themap.empty())
{
std::cout << "item[" << themap.begin()->first << "] = " << themap.begin()->second << std::endl;
std::cout << "item[" << themap.rbegin()->first << "] = " << themap.rbegin()->second << std::endl;
}
the only time you need to be careful with begin and rbegin is when your map is empty
I think you may just need to check that your containers are not empty so that begin() and rbegin() return something meaningful (defined).
Try this:
void update(void)
{
if(bid.empty() || ask.empty())
return;
// best ask code here
this->bestBid = bid.rbegin()->first;
this->bestAsk = ask.begin()->first;
this->spread = labs(this->bestAsk - this->bestBid);
}
This is not "complicated"; it simply takes some standard debugging measures
#include <map>
#include <iostream>
#include <algorithm>
#include <random>
#include <string>
#include <queue>
namespace mock {
using Order = std::string;
struct Book {
using key_type = unsigned long long;
using order_queue_type = std::queue<Order>;
using property_type = std::map<key_type, order_queue_type>;
property_type bids, asks;
void diagnose(const property_type& prop) {
for (auto it = prop.cbegin(); it != prop.cend(); ++it) {
std::clog << "\t" << it->first << '\n';
}
}
void diagnose() {
std::clog << "bids:" << '\n';
diagnose(bids);
std::clog << "asks:" << '\n';
diagnose(asks);
}
Book() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<key_type> ba_dist(0, 1000);
std::uniform_int_distribution<std::size_t> len_dist(0, 10);
auto prop_gen = [&] (property_type& prop) {
auto count = len_dist(gen);
for (std::size_t i = 0; i < count; ++i) {
auto val = ba_dist(gen);
auto pair = prop.emplace(val, order_queue_type());
if (!pair.second) {
std::clog << val << " already present" << '\n';
}
}
};
prop_gen(bids);
prop_gen(asks);
}
};
}
int main() {
mock::Book book;
book.diagnose();
}
Instead of the generator in my Book ctor, use your init routines, of course, and your Order type.
I have the following method in my program.
Weird thing is the data is not removed after I call erase.
Any idea?
map<int,obj>::iterator it = this->indexMap.find(id);
if(it != this->indexMap.end())
{
int mapSize = this->indexMap.size();
int dataSize = (*it).second.getDataMap().size();
//copy data to another node | even when it doesn't get into this if condition, it does not remove the data
if(mapSize> 1 && dataSize != 0)
{
it++;
this->copyData(id,it->first);
it--;
}
//remove peer | i've tried id and it, both does not work
this->indexMap.erase(it);
map<int,obj>::iterator iter = this->indexMap.find(id);
if(iter == this->indexMap.end())
{
cout << "ERROR" << endl;
}
}
Output:
ERROR
Thanks! :)
This block:
map<int,obj>::iterator iter = this->indexMap.find(id);
if(iter == this->indexMap.end())
{
cout << "ERROR" << endl;
}
prints out ERROR if an element with key id is not found in the map. Hence it has been removed.