考虑以下场景:有一个类CDriver
负责枚举所有连接的输出设备(由COutput
该类表示)。其代码可能如下所示:
class COutput
{
// COutput stuff
};
class CDriver
{
public:
CDriver(); // enumerate outputs and store in m_outputs
// some other methods
private:
std::vector<COutput> m_outputs;
};
现在CDriver
应该能够授予用户对枚举COutput
s 的访问权限。
实现这一点的第一种方法是返回一个指针:
const COutput* GetOutput(unsigned int idx) const
{
return idx < m_outputs.size() ? &m_outputs[idx] : nullptr;
}
在我看来,这种方法存在的问题是,如果指针由用户存储并且在CDriver
对象被销毁后仍然存在,那么它现在是一个悬空指针。这是由于在对象COutput
的析构过程中指针(对象)已被销毁CDriver
。
第二种方法是通过引用返回:
const COutput& GetOutput(unsigned int idx) const
{
return idx < m_outputs.size() ? &m_outputs[idx] : m_invalidOutput;
}
这里的问题与使用指针的方法相同。此外,它还有一个额外的警告,即不能返回真正的无效对象。如果 anullptr
作为返回指针返回,很明显它是“无效的”。nullptr
但是,在引用方面没有等价物。
继续接近第三。按值返回。
COutput GetOutput(unsigned int idx) const
{
return idx < m_outputs.size() ? &m_outputs[idx] : m_invalidOutput;
}
在这里,用户不必担心返回对象的生命周期。但是,COutput
必须复制对象,并且与参考方法类似,没有直观的方法来检查错误。
我可以继续...
例如,COutput
可以在堆上分配对象并存储在std::shared_ptr
s 中并按原样返回。然而,这会使代码非常冗长。
有什么办法可以直观地解决这个问题,并且不会引入不必要的代码冗长?