我有一个开箱即用的'Light'类,但是我知道OpenGL在任何时候都只允许激活有限数量的灯。根据glGetIntegerfv(GL_MAX_LIGHTS, ..),最大lights为8,因此无论在编译时还是在运行时,我只应允许Light类最多实例化8次。

我尝试了一种尝试解决问题的方法:

int Light::sCounter = 0;

Light::Light() : // initialiser-list
{
    sCounter++;

    if (sCounter > getMaxLightCount())
        // do something, but what?
}

其中sCounter是static int,而getMaxLightCount()调用上述的OpenGL函数。如果计数器超过最大照明灯数量,则应该发生某些情况。但是我不应该怎么回应。我不能在构造函数中返回NULL或其他任何东西,但是我一直在寻找解决问题的异常。尽管我通常不喜欢异常(exception)情况,因为这会使情况变得更加复杂。我还研究了实现Manager类的方法,但这会使事情与直觉相反,因为它实际上意味着用户不会调用Light类,而是调用Manager类。

在限制Light类的实例化数量方面,我有哪些选择?哪种解决方案对直观地重用有效?

最佳答案

如果不是太严格,则可以阻止Light类的实例化,除非使用工厂。下面的示例需要C++ 11,但没有C++ 11也可以工作(尽管需要更多工作,使用boost等)。

即使下面的示例不够用,也可能会给您一些想法。

范例程式码

#include <iostream>
#include <functional>
#include <memory>

class Light
{
public:
    using Ptr = std::unique_ptr<Light, std::function<void (Light*)>>;

    static void destroyLight(Ptr light)
    {
        // Do nothing, 'light' will be deleted when it falls out of scope
    }

    static Ptr createLight()
    {
        if (sInstanceCount < MAX_INSTANCE_COUNT)
        {
            ++sInstanceCount;
            return Ptr(new Light(), &Light::destroyLightImpl );
        }
        else
        {
            return Ptr();
        }
    }

private:
    Light() {} // Prevent others from creating instances
    ~Light() {} // Prevent others from deleting instances

    static void destroyLightImpl(Light* light)
    {
        delete light;
        --sInstanceCount;
    }

    static const int MAX_INSTANCE_COUNT = 3;
    static int sInstanceCount;
};

int Light::sInstanceCount = 0;

int main()
{
    Light::Ptr light1 = Light::createLight();
    Light::Ptr light2 = Light::createLight();
    std::cout << light1.get() << "\n";
    std::cout << light2.get() << "\n";

    Light::Ptr light3 = Light::createLight();
    Light::Ptr light4 = Light::createLight();
    std::cout << light3.get() << "\n";
    std::cout << light4.get() << "\n";

    Light::destroyLight(std::move(light3));
    Light::Ptr light5 = Light::createLight();
    std::cout << light5.get() << "\n";

    return 0;
}

示例输出

您可以在此处看到前3个实例化成功,但第4个实例却没有成功。但是,第5个灯确实起作用,因为第3个灯已被删除。
005872C0
005872F0
00587320
00000000
00587320

关于c++ - 限制Light类的实例化,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29416386/

10-13 08:18