初始化实例的构造函数内的静态成员

Initialize static member inside constructor of an instance

本文关键字:静态成员 构造函数 初始化 实例      更新时间:2023-10-16

我想在特定实例的构造函数中初始化一个静态成员变量。这是个坏主意吗?

情况如下。我有一个静态成员变量,这个类的所有实例都应该共享。通常,我只会使用一个静态初始值设定项。但是,在调用构造函数之前,我没有构造静态对象所需的必要信息。当然,我不想每次调用构造函数时都创建一个新对象,所以我想做这样的事情。

class Foo
{
    static Bar * bar;
    Foo( Xyz xyz);
};
Bar * Foo::bar = nullptr;
Foo::Foo(Xyz xyz)
{
    if (Foo::bar == nullptr)
    {
         // initialize static bar 
         Foo::bar = new Bar(xyz);
    }
}

当然,我知道对于Foo的构造函数的不同调用,xyz可能会有所不同。这对我来说并不重要。

这是糟糕的软件设计吗?在构造函数中初始化一个静态对象时,我觉得有点奇怪。但它与单例设计模式没有太大区别。所以也许没关系?

编辑

谢谢你们的评论。人们似乎不喜欢这种设计。我将对其进行修改,以便在Foo的第一个实例化之前创建一次Bar,并在Foo的构造函数中传递一个Bar *作为参数。每个Foo都有一个指向Bar的指针,我将确保所有Foo都指向同一个Bar。这样更好吗?

这是糟糕的软件设计吗?

一般来说,是的。Singleton模式或以这种方式具有静态变量被认为是糟糕的设计,原因有很多。


但它与单例设计模式没有太大区别。所以也许没关系?

如果你真的想让它成为Singleton模式,你应该使用Scott Meyer的技术:

class Foo
{
    static Bar* bar(Xyz xyz) {
        static Bar barInstance(xyz);
        return &barInstance;
    }
    Foo( Xyz xyz) : xyz_(xyz) {}
    void baz() {
        Bar* b = bar(xyz_);
        // use b ...
    }
private:
    Xyz xyz_;
};

此代码将是线程安全的,并且无需检查nullptr


尽管Bar应该自己组成一个Singleton,并且您可以随时在Foo中使用它:

class Bar {
public:
    static Bar& getInstance(Xyz xyz) {
        static Bar barInstance(xyz);
        return &barInstance;
    }
private:
    Bar(Xyz xyz) : xyz_(Xyz) {}
    Bar(const Bar&) delete;
    Bar(Bar&&) delete;
    Bar& operator=(const Bar&) delete;
    Bar& operator=(Bar&) delete;
    Xyz xyz_;
};
class Foo {
public:
    Foo(Xyz xyz) barRef(Bar::getInstance(xyz)) {
                                      // ^^^ Notice 1st instance of Foo created
                                      //     wins to create the Bar actually
    }
private:
    Bar& barRef;
};