I have a class that is a resource manager and keep the data in a map of < QString
, void*
> and the class looks like this:
template <typename R>
class ResourceManager
{
public:
ResourceManager() = default;
template <typename T>
void set(const R& name, T& object);
template <typename T>
T get(const R& name);
private:
QHash<R, void*> m_objectsMap;
};
template <typename R>
template <typename T>
void ResourceManager<R>::set(const R& name, T& object) {
m_objectsMap.insert(name, reinterpret_cast<void*>(&object));
}
template <typename R>
template <typename T>
T ResourceManager<R>::get(const R& name) {
auto it = m_objectsMap.find(name);
if (it == m_objectsMap.end()) throw std::invalid_argument("The item doesn't exists");
return *static_cast<T*>(it.value());
}
I have this struct:
struct UserData {
QString username = "";
QString permissions = "";
QString token = "";
qint64 lastTimeUsed = 0;
UserData() {}
};
And in the following function I set it up:
void f() {
UserData userData;
userData.username = userStruct.username;
userData.permissions = userStruct.permissions;
userData.token = token;
userData.updateLastTimeUsed();
qDebug() << "[Users][actionCheckToken]userData='" << userData.toString() << "'";
client.getResourceManager()->set<UserData>(USER_RESOURCEMANAGER_USERDATA_KEY, userData);
}
If I call get
right after I set it up it works, but If I call it later, in another function I receive SIGSEGV
:
1 std::__atomic_base<int>::load atomic_base.h 396 0x55555556500e
2 QAtomicOps<int>::load<int> qatomic_cxx11.h 227 0x55555556500e
3 QBasicAtomicInteger<int>::load qbasicatomic.h 103 0x555555563e5e
4 QtPrivate::RefCount::ref qrefcount.h 55 0x5555555624a6
5 QString::QString qstring.h 958 0x5555555629a9
6 Users::UserData::UserData <- my struct Users.hpp 26 0x555555578cf1
7 ResourceManager<QString>::get<Users::UserData> ResourceManager.hpp 36 0x555555578df4
8 [function from where I call]
I've checked that my pointers/references to be valid, and they are and also points to the right location(the same resource manager) but I don't know why it crash, but if I call right after I call set
it works.
Here how the function I call later looks like:
void b(Client& client) {
qDebug() << "[Users][userIsLogged]Called" << "clientID='" + client.getID() + "'";
auto userData = client.getResourceManager()->get<UserData>(USER_RESOURCEMANAGER_USERDATA_KEY);
// ...
}
The main problem is that your ResourceManager
is too generalized. Look at its name: It manages resources . That means it needs to be able to own resources , that means to take , release and destroy the resources its supposed to manage.
Your resource manager only stores and retrieves references (here: void* pointers) to some external resources. In this form it would be better named ResourceDictionary
, which implies that ownership stays outside and the user / caller is responsible to handle the lifetime of the objects.
Now, to transform what you have into a true resource manager , there is some crucial data missing: The type of the resource. Without knowing what is stored in the void *
, you can't destroy (= safely delete) it.
But you want your resource manager to be templated, so I suggest this approach:
struct tAbstractContainer
. Beware that it needs a virtual destructor! struct tQStringContainer : tAbstractContainer { QString string; };
struct tQStringContainer : tAbstractContainer { QString string; };
set()
function and also implement a destructor and assignment + copy (Rule of Three / Five). Now you can put (almost) any data into your manager and it will be correctly destroyed.
For your UserData
you'd create a struct tUserDataContainer : tAbstractContainer { UserData userdata; };
struct tUserDataContainer : tAbstractContainer { UserData userdata; };
. In f()
you'd create an instance of that container and fill its data accordingly, then throwing it into your manager.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.