我看过this thread关于单例类的实现,但不清楚如何在实践中使用它。为了使上下文更具体,请说我有一个许多不同类需要访问的输入流std::istream
实例,但是我没有为每个类构造函数传递它,而是考虑使用单例类{{1}包装此信息。所以客户可以致电:
Connection
我的问题有两个方面:(1)这是一个正确使用单例类(2)来实现这个,我尝试过这样的事情:
Connection.getInstance().get_input_stream();
首先,此代码由于某种原因无法编译。其次,你必须在class Connection {
public:
static Connection& getInstance() {
static Connection instance; // Guaranteed to be destroyed
return instance;
}
std::istream& get_istream() {
return is;
}
void set_istream(std::istream & stream) {
is = stream;
}
private:
std::istream& is;
}
可用之前调用它感觉很尴尬。有没有更好的方法来完成这项工作?感谢。
编辑:显然,正如许多人所指出的那样,尝试分配引用是我的愚蠢行为。第二部分是如何将set_istream()
信息传递给单例 - 似乎不值得,这表明这可能是使用它的错误案例。谢谢大家的回答。
答案 0 :(得分:3)
创建后无法修改引用,因此要“设置”istream,您必须将其传递给ctor:
class Connection {
/* ... */
Connection(std::istream & stream) : is(stream) {}
private:
std::istream& is;
}
然而,这引发了一个问题,即当你创建一个静态实例时如何将正确的流传递给ctor - 而答案就是它是非平凡的(充其量)。您可以使用指针而不是引用,因此您可以创建一个对象并稍后将其指向实际流,但此时您基本上会遇到麻烦(需要两阶段初始化)。
最终,这不值得。我的建议是反对在这种情况下使用单身人士。看起来它正在增加相当多的工作,并提供很少(如果有的话)作为回报。
相当多的人开始建议不要使用singleton
,至少在C ++中,坦率地说,我倾向于大多数时候都同意。这种情况就是为什么 - 你通常最终得到的回报很少。
答案 1 :(得分:1)
我总是被告知要避免单身,所以这有两个部分:
class Connection {
public:
static std::istream& getInstance() {
assert(is);
return *is;
}
static void set_istream(std::istream & stream) {
is = &stream;
}
private:
static std::istream* is;
}
std::istream* Connection::is = NULL;
int main() {
Connection::set_istream(std::cin);
Connection::getInstance() << "moomoomoo\n";
}
注意我创建了流static
,一个指针和全局(所以它实际上是一个单例。你的代码....不是。没有理由让那么多的引用存在,如果你有is = blah
其中is
是一个引用,不重置引用。它会将权限复制到左边,对于流来说,没有意义并且不会甚至编译。
当然,单身人士很糟糕。使用全局变量或非单身变量。 (这是一个全球性的,只能创建一次)
//params are ignored after first call
template<typename... Ts>
std::istream& Connection(Ts... Us) {
static std::ifstream c(std::forward<Ts>(Us)...);
return c;
}
int main() {
//construct and use
Connect("input.txt") << "thing" << std::endl;
Connect() << "stuff";
Connect("this is ignored") << "IM A COW STOP SAYING IM A DUCK";
}
答案 2 :(得分:1)
由于两个原因,它无法编译。首先,调用语法有一个非常小的问题。修复如下:
Connection::getInstance().get_input_stream();
其次是你不能分配给引用,它必须在构造时初始化。因为你的构造函数是从getInstance的中间调用的,所以这是不切实际的。改为使用指针。
是的,在单件可用之前需要调用set_istream很尴尬,但这似乎是不可避免的。