关于使用C ++单例类

时间:2012-02-16 18:22:04

标签: c++ singleton

我看过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()信息传递给单例 - 似乎不值得,这表明这可能是使用它的错误案例。谢谢大家的回答。

3 个答案:

答案 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很尴尬,但这似乎是不可避免的。