【发布时间】:2016-12-15 01:54:20
【问题描述】:
这是一个类,Unique,用于创建独特的对象。对象是通过工厂方法Unique::Get 创建的,并由传递给此方法的值唯一。该方法检查唯一对象集合Unique::cache中是否存在具有此值(键)的对象,如果没有,则创建一个新对象并插入到集合中。
我希望这个类对用户的使用非常有限。具体来说,用户不应该通过调用Get 方法来复制该类的对象或创建对象。为了实现这一点,我将构造函数和赋值运算符声明为私有的。但是当我这样做时,我不能在类本身中使用 std::set::emplace,因为构造函数是私有的。
可能的解决方案是将std::set 类声明为朋友,但这将允许用户也可以将此容器与我的类一起使用。这可能是有害的。
有没有更好的办法?
#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;
}
【问题讨论】:
-
如果你不能复制它们,那么你打算如何从
Unique::Get返回的位置获取一个到集合中?可以移动吗? -
emplace 方法在原地构造元素,它不需要复制构造函数。但它需要一个普通的构造函数才能访问,这就是问题所在。我相信有一些常见的模式可以解决它。
-
显然,如果你不允许你的类的用户构造实例,你就不允许他们在集合中构造实例,因为那样他们就可以做你正在做的事情试图阻止他们这样做。
-
所以您似乎希望您的用户能够有时构造实例(特别是当这些实例位于集合中时)。您是否还希望用户能够构建实例?
-
我的英语远非完美,抱歉。但我想我已经非常清楚地解释了我的意图。我不希望我的类的用户能够以任何直接或间接的方式使用构造函数,除非通过调用工厂方法。并且这个方法应该能够向集合中添加一个元素(它是类的成员)。