考虑以下情况:有一个类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
对象后,仍然存在已经被摧毁,它现在是一个摇摆不定的指针。这是因为在CDriver
对象的析构函数中指针对象(COutput
对象)已被破坏。
这样做将是参考返回的第二种方式:
const COutput& GetOutput(unsigned int idx) const
{
return idx < m_outputs.size() ? &m_outputs[idx] : m_invalidOutput;
}
这里同样的问题适用,与指针的方法。此外它还有一个额外的警告,即不能返回真正的无效对象。如果nullptr
作为返回指针返回,则很明显它是“无效的”。然而,在涉及到参考文献时,没有等同于nullptr
。
继续前进到第三种方法。按价值回报。
COutput GetOutput(unsigned int idx) const
{
return idx < m_outputs.size() ? &m_outputs[idx] : m_invalidOutput;
}
在这里,用户不必担心返回对象的生命周期。但是,COutput
对象必须被复制,并且与参考方法相似,没有直观的方法来检查错误。
我可以继续下去...
例如,COutput
对象可以在堆中分配,并存储在std::shared_ptr
S和返回等。但是,这会使代码非常冗长。
有没有什么办法直观地解决这个问题,而且不会引入不必要的代码冗长?
这取决于具体情况。针对不同情况的不同退货方式。我认为你需要更具体。 – Galik
通过引用/值返回的两种可能的解决方案:1)抛出索引超出范围的异常(这是['std :: vector :: at'](http://en.cppreference.com/w/cpp/container/vector/at)does),或者2)具有未定义的行为来引发越界(这是['std :: vector :: operator []'](http://en.cppreference.com/w/cpp/container/vector/operator_at))。 – Frxstrem
@Frxstrem但是这仍然不能解决对象必须被复制的问题 – Philinator