C++ 参照对象的STL容器
我知道STL容器复制对象。所以说我有一个C++ 参照对象的STL容器,c++,stl,reference,pass-by-reference,C++,Stl,Reference,Pass By Reference,我知道STL容器复制对象。所以说我有一个 list<SampleClass> l; 将制作一份t。如果SampleClass很大,那么它将非常昂贵 但是如果我把l声明为引用的容器 list<SampleClass&> l; 它会避免复制对象吗?遗憾的是,它不会编译(至少使用stlport)。但另一种选择是将指向对象的指针存储在容器中,这样可以很好地编译 这将在代码周围留下一点额外的语法噪音——为了将它们插入到容器中,您必须使用新的东西 std::list<
list<SampleClass> l;
将制作一份t。如果SampleClass很大,那么它将非常昂贵
但是如果我把l声明为引用的容器
list<SampleClass&> l;
它会避免复制对象吗?遗憾的是,它不会编译(至少使用stlport)。但另一种选择是将指向对象的指针存储在容器中,这样可以很好地编译 这将在代码周围留下一点额外的语法噪音——为了将它们插入到容器中,您必须使用新的东西
std::list<class_type*> l;
l.push_back(new class_type);
std::list l;
l、 推回(新的类别类型);
但是,虽然现在不会复制对象,但在销毁列表时也不会自动为您清理对象。智能指针将为您解决这个问题,但代价是更多的语法噪音。由于无法复制std::auto_ptr,所以无法将其放入标准容器中,因此必须使用稍重的重量提升表,即共享指针
std::list<boost::shared_ptr<class_type> > l;
l.push_back(boost::shared_ptr<class_type>(new class_type));
std::list l;
l、 push_back(boost::shared_ptr(新类类型));
共享点确实会产生一些额外的开销,但这是最小的。标准库容器要求其类型是可复制的;由于引用不是,所以您不能首先将它们存储在容器中。您可以存储指针,只要您对对象生命周期非常小心。Boost有一些指针容器来帮助实现这一点,或者您有智能指针。但是,请注意,
auto\u ptr
是不可复制的(正如标准为此定义的那样),因此shared\u ptr
和unique\u ptr
现在是您的最佳选择。两者在C++11中都是标准的,前者通过C++03中的boost得到支持 如果您知道自己在做什么,可以使用std::reference\u wrapper
:
#include <functional>
#include <vector>
int main()
{
std::vector<std::reference_wrapper<int>> iv;
int a = 12;
iv.push_back(a); // or std::ref(a)
// now iv = { 12 };
a = 13;
// now iv = { 13 };
}
#包括
#包括
int main()
{
std::载体iv;
INTA=12;
iv.向后推(a);//或标准::参考(a)
//现在iv={12};
a=13;
//现在iv={13};
}
当然,请注意,如果引用的任何变量在您仍保留对它们的引用时超出范围,则所有这些都将崩溃。您需要一个指针容器:
list<SampleClass*> l;
列表l;
现在您有了智能指针,您可以使用它进行内存管理,并从中获取原始指针以在STL容器中使用。通过这种方式,您可以将所有权排除在容器之外
std::list<class_type*> l;
l.push_back(new class_type);
在这里,我有一个独特的树,但使用STL堆栈来存储原始指针
void TreeTraversal(unique_ptr<BinaryTreeNode>& root) {
stack<BinaryTreeNode *> _stack;
BinaryTreeNode *p = root.get();
_stack.push(p);
while(!_stack.empty()) {
p = _stack.top();
_stack.pop();
...
_stack.push(p->left);
_stack.push(p->right);
}
}
int main() {
unique_ptr<BinaryTreeNode> root = unique_ptr<BinaryTreeNode>(new BinaryTreeNode(...));
TreeTraversal(root);
}
void TreeTraversal(唯一的\u ptr&root){
堆栈(u堆栈),;
BinaryTreeNode*p=root.get();
_栈推(p);
而(!\u stack.empty()){
p=_stack.top();
_stack.pop();
...
_栈.推(p->左);
_栈.推(p->右);
}
}
int main(){
unique_ptr root=unique_ptr(新的二元三萜(…));
树根;
}
事实上,现在我想起来了。。。考虑到11中按函数分解需求的方式,如果您将自己限制在一个足够小的操作子集内,则可能存储一个引用类型,但子集将非常有限。正确:我认为reference\u wrapper
s应该优先于原始指针,为了清楚地传达非所有权,请避免使用粗糙的指针语法(交换条件是中断auto
并有时不得不使用.get()
),并避免未初始化指针或nullptr
或意外执行指针算术等。
void TreeTraversal(unique_ptr<BinaryTreeNode>& root) {
stack<BinaryTreeNode *> _stack;
BinaryTreeNode *p = root.get();
_stack.push(p);
while(!_stack.empty()) {
p = _stack.top();
_stack.pop();
...
_stack.push(p->left);
_stack.push(p->right);
}
}
int main() {
unique_ptr<BinaryTreeNode> root = unique_ptr<BinaryTreeNode>(new BinaryTreeNode(...));
TreeTraversal(root);
}