Here is a class, Unique
, for creating unique objects. Objects are created through the factory method Unique::Get
and are uniqued by the value passed to this method. The method checks if there is an object with this value (a key) in the set of unique objects Unique::cache
, and if not, creates a new object and inserts in into the set.
I want this class to be of very limited use to users. Specifically, users should not be able to copy objects of this class or create objects not by means of calling the Get
method. To achieve this I declare the constructors and the assignment operator as private. But when I do this, I can not use std::set::emplace within the class itself, because the constructor is private.
Possible solution would be declaring the std::set
class as a friend, but that would allow users to also use this container with my class. This can be harmful.
Is there a better way?
#include <set>
#include <iostream>
#include <iomanip>
class Unique {
public:
// user accessible methods
static const Unique &Get(int key);
bool operator==(const Unique &other) const {
return this == &other;
}
private:
// user inaccessible methods
Unique(int key) : key_(key) {}
Unique(const Unique &) = delete;
Unique &operator=(const Unique &) = delete;
int key_;
private:
// cache related stuff
struct Identity {
Identity(int key) : key_(key) {}
int key_;
};
struct Compare {
struct is_transparent {};
bool operator()(const Identity &lhs, const Unique &rhs) const {
return lhs.key_ < rhs.key_;
}
bool operator()(const Unique &lhs, const Identity &rhs) const {
return lhs.key_ < rhs.key_;
}
bool operator()(const Unique &lhs, const Unique &rhs) const {
return lhs.key_ < rhs.key_;
}
};
static std::set<Unique, Compare> cache;
};
std::set<Unique, Unique::Compare> Unique::cache;
const Unique &Unique::Get(int key) {
Identity identity(key);
auto it = cache.find(identity);
if (it == cache.end()) {
it = cache.emplace(key).first;
}
return *it;
}
int main() {
const Unique &c1 = Unique::Get(1);
const Unique &c2 = Unique::Get(1);
std::cout << std::boolalpha << (c1 == c2) << std::endl;
}