函数返回引用,失败时返回什么

Function returning reference, what to return on failure?

本文关键字:返回 什么 失败 引用 函数      更新时间:2023-10-16

作为我用插件瞄准的框架设计的结果,我已经将我的一部分代码实现为单例。这个类负责处理与外部程序的连接,我与外部程序在框架内进行通信。

启用外部通信是一个运行时设置,然而,如果它被禁用,我不想允许从框架内的模型访问它。我使用这里经常推荐的版本来实现它:

class Communicator {
public: 
    static Communicator& getInstance() {
        static Communicator instance;
        return instance;
    }
    // ...
private: 
    static bool ServiceEnabled;
    // Constructors, operator=, etc ...
}

现在,假设ServiceEnabledfalse,我不想让getInstance返回一个有效的Communicator。但是由于我返回一个引用,我不能简单地返回0或诸如此类的…什么是正确的行为?请注意,即使ServiceEnabled为假,继续执行也是完全有效的,所以如果它为假,我就不能中止。

添加一个公共函数

static bool IsServiceEnabled();

并在getInstance中抛出异常,当ServiceEnabled == false;

实际上,有很多可能性…这是一个列表的开头,没有特别的顺序。

<<p> 指针/strong>
class Communicator {
public:
  static Communicator const* Instance(); // returns 0 if not Enabled
};

这实际上可以被一个"更安全"的指针类型所取代(如果指针为空并且有人试图使用它,则断言/抛出)。

Query + Throw

class Communicator {
public:
  static bool IsEnabled();
  static Communicator const& Instance(); // throw if not Enabled
};

空对象

class Communicator {
public:
  static Communicator const& Instance(); //returns a null instance if not Enabled
  void doit() { if (!enabled) { return; } }
};

我个人不太喜欢最后一个,因为隐藏它未启用的事实可能会阻止用户早期注意到问题。想象一个事务系统,当它把所有的东西都发送到/dev/null时,确信它已经注册了它的事务…

正确的行为是在遇到故障时抛出异常:

#include <stdexcept>
class Communicator {
public: 
    static Communicator& getInstance() {
        static Communicator instance;
        if (ServiceEnabled)
          return instance;
        else
          throw std::exception("Get communicator while service is not enabled");
    }
    // ...
private: 
    static bool ServiceEnabled;
    // Constructors, operator=, etc ...
}

我会再次考虑设计决策,然后可能会创建一个异常类并抛出它。这当然需要处理另一端可能出现的异常。

也许您应该考虑ServiceEnabled为false的通信器为" valid "

要实现,你需要一个方法bool IsEnabled(),你的其他方法需要检查服务是否被启用,大多数情况下,如果没有,立即返回。

如果没有启用,为什么不让类忽略所有有副作用的调用?这样你就可以调用你想要的所有函数,而不必担心它是打开还是关闭。提供一个"IsServiceEnabled"(作为Henrik的回答)来允许用户知道它是否应该进行通信。

如果您真的希望能够在运行时打开和关闭通信,您可能需要担心这样一个事实,即用户可以在启用Communicator引用时保存它,并在稍后禁用它时尝试使用它。当然,这个问题并不是单例独有的。
你可以引入另一个间接层来处理它:

class CommunicatorImpl
{
public:
    virtual bool isEnabled() const = 0;
    virtual void doSomething() = 0;
};
class CommunicatorImpl_Enabled : public CommunicatorImpl
{
    public:
        virtual bool isEnabled() const { return true; }
        virtual void doSomething()  { /* Do something... */}
};

class CommunicatorImpl_Disabled : public CommunicatorImpl
{
    public:
        virtual bool isEnabled() const { return false; }
        virtual void doSomething()  { throw CommunicationIsDisabled("SRY"); }
};

class Communicator {
public: 
    static Communicator& getInstance() {
        static Communicator instance;
        return instance;
    }
    void enable () { m_impl = &m_enabled; }
    void disable () { m_impl = &m_disabled; }
    bool isEnabled() const { return m_impl->isEnabled(); }
    void doSomething() { m_impl->doSomething(); }
private: 
    CommunicatorImpl* m_impl;
    CommunicatorImpl_Enabled m_enabled;
    CommunicatorImpl_Disabled m_disabled;
}