我有一个类 (
A
),它将拥有另一个类 (B
) 的一组实例的内存。 A
会将 B
的实例存储为一组 std::unique_ptr<B>
。
我希望
A
能够返回对这些 B 对象的一组原始指针的引用(即我不希望任何所有权转移)。最好的方法是什么?
class A
{
private:
std::set<std::unique_ptr<B>> _Bs;
public:
std::set<B*>& getBs() { ???? };
}
我可以创建一个新向量:
class A
{
private:
std::set<std::unique_ptr<B>> _Bs;
std::set<B*> _rawBs;
public:
std::set<B*>& getBs() { return _rawBs; };
}
std::set<B*>
A::A()
{
std::transform(_Bs.begin(),
_Bs.end(),
std::inserter(_rawBs, _rawBs.begin()),
[](auto uniq_ptr) { uniq_ptr.get(); }
}
但是将这些指针存储两次似乎有点笨拙......
你应该添加一个成员函数:
const std::set<std::unique_ptr<B>>& getBs() {
return m_bs;
}
有几点需要注意:
不幸的是,您无法返回类似
std::span
的内容,并且必须返回对 const std::set
的引用。这会泄露更多的实现细节,但这是必要的,因为集合不是连续的容器。
您仍然可以返回一个包含所有指针副本的
std::vector<B*>
,但这会更昂贵。
A
const std::set
只允许您以 const std::unique_ptr
的形式访问内部元素,因此尽管暴露了 std::unique_ptr
,但没有所有权被转移。所有权转让还需要能够修改 std::unique_ptr
。
不应将名称
_Bs
用于数据成员,因为下划线后跟大写字母可构成保留标识符。请参阅在 C++ 标识符中使用下划线的规则是什么?。
最流行的成员命名方案(如果您给他们前缀或后缀)是前缀 m_
。
我希望 A 能够返回对 B 对象的一组原始指针的引用
这是一个糟糕的计划。如果调用者修改了该集合,您会怎么做?
您可以按值返回指针视图。
class A
{
private:
std::set<std::unique_ptr<B>> Bs;
public:
auto getBs() const {
return Bs | std::views::transform([](auto & ptr){ return ptr.get(); });
};
};
如果您的
std::unique_ptr<B>
保证不为空,您可以通过将 ptr.get()
替换为 *ptr
来返回引用视图。