我开始使用c ++ 11功能,我喜欢使用智能指针只拥有对象。这是我的班级:
class MyClass {
public:
vector<MyObject*> get_objs() const;
private:
vector<unique_ptr<MyObject>> m_objs;
};
语义是MyClass
拥有一系列MyObject
,它们是通过make_unique
()创建的。 get_objs()
返回原始指针的向量,以便各种调用者更新对象。因为这些调用者不拥有对象,所以函数不会返回vector<unique_ptr>.
但这意味着我需要像这样实施get_objs()
:
vector<MyObjects*> MyClass::get_objs() const
{
vector<MyObjects*> ret;
for (auto obj : my_objs) {
ret.push_back(obj->get());
}
return ret;
}
我关心的是get_objs()
经常被调用,每次都有构造这个原始指针向量的开销。
我能在这做些什么吗?如果没有c ++ 11技巧来节省开销,我应该首先在vector<MyObject*>
使用m_objs
类型吗?
UPDATE 1
使用operator[]
的Jonathan Wakely解决方案改进了我的方法,以便调用者可以直接访问单个对象。
还有其他解决方案吗?我不介意去所有调用get_objs(),
的地方,但想看看是否有更好的解决方案。
另一个注意事项 - 我不能使用BOOST,只是我必须忍受的一些限制。
答案 0 :(得分:6)
首先,您可以使用ret.reserve(m_objs.size())
预先分配正确数量的元素。
或者,不要为调用者返回一个向量直接迭代的向量,而是显示类似向量的接口:
class MyClass {
public:
struct iterator;
iterator begin();
iterator end();
MyObject* operator[](size_t n) { return m_objs[n].get(); }
private:
vector<unique_ptr<MyObject>> m_objs;
};
这允许调用者直接修改对象,而不是获取指针容器。
答案 1 :(得分:4)
class MyClass {
public:
std::vector<std::unique_ptr<MyObject>> const& get_objs() const {
return m_objs;
}
private:
std::vector<std::unique_ptr<MyObject>> m_objs;
};
const std::unique_ptr<MyObject>&
无法窃取所有权,与std::unique_ptr<const MyObject>
不同。 const std::vector<std::unique_ptr<MyObject>>&
只能授予const
对其数据的访问权限。
答案 2 :(得分:3)
如果您可以使用Boost,请尝试使用indirect_iterator(http://www.boost.org/doc/libs/1_55_0b1/libs/iterator/doc/indirect_iterator.html)。您需要在类中定义迭代器,开始和结束:
typedef boost::indirect_iterator<vector<unique_ptr<MyObject>::iterator> iterator;
iterator begin() { return make_indirect_iterator(m_objs.begin()); }
然后你的类暴露迭代器,其值是MyObject
的引用(不是指针!)。您可以直接迭代和访问向量的元素。
答案 3 :(得分:2)
为了记录,我认为像Jonathan Wakely's answer之类的东西是要走的路。但是,由于您要求更多可能性,另一个是使用shared_ptr
而不是unique_ptr
:
class MyClass {
public:
const vector<shared_ptr<MyObject>>& get_objs() const {
return m_objs;
}
private:
vector<shared_ptr<MyObject>> m_objs;
};
这可以通过两种方式改进原始代码:
get_objs
中建立新的向量;你可以只返回你所拥有的那个引用。shared_ptr
可确保在所有引用之前不删除指向的对象已被释放。另一方面,get_objs
可能不应该是const
。调用代码不能修改向量本身,但可以修改它包含的MyObject
。
答案 4 :(得分:0)
另一种方法是根本不返回任何对象并封装您存储数据的方式(告诉不要问)。 通常当你得到这些项目时,你最终都会遍历它们,所以将它包装在类中并传入你希望对象通过的函数是有意义的。
非提升方式将类似于
void MyClass::VisitItems(std::function<void, MyObject&> f)
{
for (auto obj : my_objs)
{
f(*obj);
}
}