【发布时间】:2017-08-08 21:39:56
【问题描述】:
考虑以下场景:有一个类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 应该能够授予用户访问枚举的COutputs 的权限。
实现这一点的第一种方法是返回一个指针:
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;
}
这里的问题与使用指针的方法相同。此外,它还有一个额外的警告,即不能返回真正的无效对象。如果将nullptr 作为返回指针返回,则很明显它是“无效的”。但是,在引用方面,没有与 nullptr 等效的选项。
继续接近第三名。按值返回。
COutput GetOutput(unsigned int idx) const
{
return idx < m_outputs.size() ? &m_outputs[idx] : m_invalidOutput;
}
在这里,用户不必担心返回对象的生命周期。但是,COutput 对象必须被复制,并且与引用方法类似,没有直观的方法来检查错误。
我可以继续...
例如,COutput 对象可以在堆上分配并存储在std::shared_ptrs 中,然后按原样返回。但是,这会使代码非常冗长。
有没有什么办法可以直观地解决这个问题,又不会引入不必要的代码冗长?
【问题讨论】:
-
视具体情况而定。不同的情况有不同的退货方式。我认为您需要更具体。
-
通过引用/值返回的两种可能的解决方案:1) 对超出范围的索引抛出异常(这是
std::vector::at所做的),或 2) 对超出范围的索引有未定义的行为(这就是std::vector::operator[]所做的)。 -
@Frxstrem 但这仍然不能解决必须复制对象的问题
-
为什么复制对象有问题?
-
如果您想返回一个对象而不复制它或放弃所有权,请考虑
std::weak_ptr。
标签: c++ pointers reference return-by-value