TransWikia.com

C++ thread lambda captured object can read but cannot erase

Stack Overflow Asked by nicram on November 10, 2021

I’m new in c++ so my problem could be very simple but I cannot solve it.
In my constructor I want to start detached thread which will be looping with class variable and removing old data.
userCache.hpp

struct UserCacheItem {
    long m_expires;
    oatpp::Object<User> m_user;

    UserCacheItem(const long expires, const oatpp::Object<User> &user);
};

class UserCache {
private:

    std::map<std::string, std::shared_ptr<UserCacheItem> > m_userCacheItem;

public:
    UserCache();

    void cacheUser(std::string payload, std::shared_ptr<UserCacheItem> &userCacheItem);
};

userCache.cpp

UserCache::UserCache()
{
    std::thread thread([this]() mutable {
        while (true){
            auto curTimestamp = std::chrono::seconds(std::chrono::seconds(std::time(nullptr))).count();

            for(auto &elem : m_userCacheItem){
                if (curTimestamp > elem.second->m_expires){
                    std::cout << "Erasing element: " << elem.second->m_expires << std::endl;
                    m_userCacheItem.clear();
                }
            }

            std::cout << "Cache size: " << m_userCacheItem.size() << " Current timestamp: " << curTimestamp << std::endl;
            std::this_thread::sleep_for(std::chrono::seconds(10));
        };
    });
    thread.detach();
}

When I reach line m_userCacheItem.clear(); I get segmentation fault. Ofcourse if if block is false line with cout cache sizie is printed properly.
So I can read my variable but I cannot modify it 🙁

Where I’m making error?

One Answer

You cannot modify the map while you're iterating it

            for(auto &elem : m_userCacheItem){
                if (curTimestamp > elem.second->m_expires){
                    std::cout << "Erasing element: " << elem.second->m_expires << std::endl;
                    m_userCacheItem.clear();
                }
            }

If you want to erase an element, use std::map::erase:

for(auto & it = m_userCacheItem.begin(); it != m_userCacheItem.end();) {
    if(condition) {
        it = m_userCacheItem.erase(it);
    } else {
        ++it;
    }
}

Answered by PirklW on November 10, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP