I have a class (A
) that will own the memory for a set of instances of another class (B
). A
will store its instances of B
as a set of std::unique_ptr<B>
.
I want A
to be able to return a reference to a set of raw pointers to those B objects, (i.e. I don't want any transfer of ownership). What is the best way to do this?
class A
{
private:
std::set<std::unique_ptr<B>> _Bs;
public:
std::set<B*>& getBs() { ???? };
}
I could create a new vector:
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(); }
}
But it seems a bit janky to store these pointers twice...
You should add a member function:
const std::set<std::unique_ptr<B>>& getBs() {
return m_bs;
}
There are a few things to note:
Unfortunately you cannot return something like std::span
and have to return a reference to a const std::set
. This leaks more implementation details, but is necessary because sets aren't contiguous containers.
You can still return a std::vector<B*>
that contains a copy of all the pointers, but this would be more expensive.
A const std::set
only lets you access the elements inside as const std::unique_ptr
, so no ownership is being transferred, despite exposing the std::unique_ptr
. Transfer of ownership would also require the ability to modify the std::unique_ptr
.
You should not use the name _Bs
for a data member because an underscore followed by a capital letter makes for a reserved identifier. See What are the rules about using an underscore in a C++ identifier?.
The most popular naming scheme for members (if you give them a prefix or suffix) is the prefix m_
.