让
class A
{
std::vector<std::shared_ptr<int>> v_;
};
现在,我想使用两个公共成员函数
添加对v_
的访问权限
std::vector<std::shared_ptr<int>> const & v() { return v_; }
和
std::vector<std::shared_ptr<int const> const & v() const { TODO }
我无法用TODO
取代return v_;
。
一种选择是不返回引用而是复制。除了明显的性能损失之外,这也会使界面变得不那么理想。
另一个选择是让TODO
等于return reinterpret_cast<std::vector<std::shared_ptr<int const>> const &>(v_);
我的问题是,这是未定义的行为吗?或者,是否有更好的选择,最好不使用reinterpret_cast
?
答案 0 :(得分:6)
避免复制容器的一种方法是提供转换迭代器,在迭代引用时转换元素:
#include <vector>
#include <memory>
#include <boost/iterator/transform_iterator.hpp>
class A
{
std::vector<std::shared_ptr<int> > v_;
struct Transform
{
template<class T>
std::shared_ptr<T const> operator()(std::shared_ptr<T> const& p) const {
return p;
}
};
public:
A() : v_{std::make_shared<int>(1), std::make_shared<int>(2)} {}
using Iterator = boost::transform_iterator<Transform, std::vector<std::shared_ptr<int> >::const_iterator>;
Iterator begin() const { return Iterator{v_.begin()}; }
Iterator end() const { return Iterator{v_.end()}; }
};
int main() {
A a;
// Range access.
for(auto const& x : a)
std::cout << *x << '\n';
// Indexed access.
auto iterator_to_second_element = a.begin() + 1;
std::cout << **iterator_to_second_element << '\n';
}
答案 1 :(得分:3)
暂不讨论是否应该返回对成员的引用......
std::vector
已经将自己的const
限定符传播给它返回的引用,指针和迭代器。唯一的障碍是让它进一步传播到std::shared_ptr
的指针类型。您可以使用类似std::experimental::propagate_const
的类(希望可以标准化)来促进这一点。它就像它的名字所暗示的那样,对于它包装的任何指针或类指针对象。
class A
{
using ptr_type = std::experimental::propagate_const<std::shared_ptr<int>>;
std::vector<ptr_type> v_;
};
因此TODO
可以成为return v_;
,并且对指定者的任何访问(例如在您希望支持的范围内)将保持常量。
唯一需要注意的是它只是一个可移动的类型,因此复制一个向量的元素将需要更多的工作(例如,通过调用std::experimental::get_underlying
)与向量本身的元素类型。