My application starts several similar processes. First one creates a "global" temp file that they all red/write. When last process is destroyed, this file needs to be deleted. Later more processes may be spun up and this file should be re-created. From various examples I came up with a manager class that creates shared_ptr's with custom deleter (removing the file) and holds week_ptr to these objects to be able to hand them out upon request. This works but I'm wondering if there is a better approach, or any pitfalls can be spotted in my code.
#include <iostream>
#include <memory>
#include <string>
#include <set>
bool ptr_less(std::weak_ptr<std::string> lhs, std::weak_ptr<std::string> rhs) {
auto left = lhs.lock();
auto right= rhs.lock();
if (!left || !right)
return left < right;
return *left < *right;
}
struct Manager {
std::shared_ptr<std::string> get(const std::string& filename) {
auto result = resources.find( std::weak_ptr<std::string>(std::make_shared<std::string>(filename)) );
if (result != resources.end()) {
std::cout << "Exists: " << filename << std::endl;
if (auto sp = result->lock())
return sp;
resources.erase(result);
}
// Create new object to manage, auto deleting
std::shared_ptr<std::string> ptr(new std::string(filename),
[](std::string* str) { std::cout << "remove: " << *str << std::endl; delete str; });
resources.emplace(std::weak_ptr<std::string>(ptr));
//cleanup null pointers
for (auto iter=resources.begin(); iter != resources.end(); ) {
if (!iter->lock())
iter = resources.erase(iter);
else
++iter;
}
return ptr;
}
//Keep track of files to share. std::set comparing values not pointers
std::set<std::weak_ptr<std::string>, decltype(ptr_less)*> resources{ptr_less};
};
static Manager custodian;
struct User {
User(std::string name) : mName(std::move(name)) {
std::cout << "New user: " << mName << std::endl;
mGlob = custodian.get("global.json");
mSet = custodian.get("settings-" + mName + ".json");
mVal = custodian.get("values-" + mName + ".json");
}
~User() {
std::cout << "~User(): " << mName << std::endl;
}
std::shared_ptr<std::string> mGlob;
std::shared_ptr<std::string> mSet;
std::shared_ptr<std::string> mVal;
std::string mName;
};
int main()
{
using namespace std;
User* ps3 { nullptr };
{
User ps1("ps1");
User ps2("ps2");
ps3 = new User("ps3");
}
delete ps3;
cout << "Resources size: " << custodian.resources.size() << endl;
User ps1("ps1");
cout << "Resources size: " << custodian.resources.size() << endl;
return 0;
}
Aucun commentaire:
Enregistrer un commentaire