您好我今天问了一个关于How to insert different types of objects in the same vector array 的问题,我在该问题中的代码是
gate* G[1000];
G[0] = new ANDgate() ;
G[1] = new ORgate;
//gate is a class inherited by ANDgate and ORgate classes
class gate
{
.....
......
virtual void Run()
{ //A virtual function
}
};
class ANDgate :public gate
{.....
.......
void Run()
{
//AND version of Run
}
};
class ORgate :public gate
{.....
.......
void Run()
{
//OR version of Run
}
};
//Running the simulator using overloading concept
for(...;...;..)
{
G[i]->Run() ; //will run perfectly the right Run for the right Gate type
}
我想使用载体,所以有人写道我应该这样做:
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
然后他和其他许多人建议我最好使用Boost pointer containers
或shared_ptr
。我花了最近3个小时阅读这个主题,但文档对我来说似乎很先进。 ****任何人都可以给我一个shared_ptr
用法的小代码示例以及他们建议使用shared_ptr
的原因。还有其他类型,例如ptr_vector
,ptr_list
和ptr_deque
** **
Edit1:我也读过一个代码示例,包括:
typedef boost::shared_ptr<Foo> FooPtr;
.......
int main()
{
std::vector<FooPtr> foo_vector;
........
FooPtr foo_ptr( new Foo( 2 ) );
foo_vector.push_back( foo_ptr );
...........
}
我不懂语法!
答案 0 :(得分:113)
使用vector
shared_ptr
可以消除内存泄漏的可能性,因为您忘记了遍历向量并在每个元素上调用delete
。让我们逐行浏览一个稍微修改过的示例版本。
typedef boost::shared_ptr<gate> gate_ptr;
为共享指针类型创建别名。这样可以避免因输入std::vector<boost::shared_ptr<gate> >
并忘记关闭大于号之间的空格而导致C ++语言的丑陋。
std::vector<gate_ptr> vec;
创建boost::shared_ptr<gate>
个对象的空向量。
gate_ptr ptr(new ANDgate);
分配新的ANDgate
实例并将其存储到shared_ptr
中。单独执行此操作的原因是为了防止操作抛出时可能发生的问题。在这个例子中这是不可能的。 Boost shared_ptr
"Best Practices"解释为什么将最佳做法分配到一个独立的对象而不是临时对象。
vec.push_back(ptr);
这会在向量中创建一个新的共享指针,并将ptr
复制到其中。 shared_ptr
内容中的引用计数可确保ptr
内的已分配对象安全地传输到向量中。
没有解释的是shared_ptr<gate>
的析构函数确保删除分配的内存。这是避免内存泄漏的地方。 std::vector<T>
的析构函数确保为向量中存储的每个元素调用T
的析构函数。但是,指针的析构函数(例如gate*
)不会删除已分配的内存。这就是您要使用shared_ptr
或ptr_vector
来避免的。
答案 1 :(得分:40)
我将补充说,关于shared_ptr
的一个重要事项是只使用以下语法永远构建它们:
shared_ptr<Type>(new Type(...));
这样,指向Type
的“真实”指针对您的作用域是匿名的,并且共享指针只保留 。因此,你不可能意外地使用这个“真正的”指针。换句话说,永远不要这样做:
Type* t_ptr = new Type(...);
shared_ptr<Type> t_sptr ptrT(t_ptr);
//t_ptr is still hanging around! Don't use it!
虽然这样可行,但您现在在函数中有一个Type*
指针(t_ptr
),它位于共享指针之外。在任何地方使用t_ptr
是危险的,因为你永远不知道持有它的共享指针什么时候可能会破坏它,你就会发生段错误。
其他类返回给你的指针也是如此。如果你没有写一个班级给你一个指针,那么把它放在shared_ptr
中通常是不安全的。除非您确定该类不再使用该对象,否则不会。因为如果你把它放在shared_ptr
中,并且它超出了范围,那么当该类可能仍需要它时,该对象将被释放。
答案 2 :(得分:19)
学习使用智能指针是我认为成为一名称职的C ++程序员最重要的步骤之一。如您所知,每当您在某个时刻新建一个对象时,您想要将其删除。
出现的一个问题是,除了异常之外,很难确保在所有可能的执行路径中始终只释放一次对象。
这就是RAII的原因:http://en.wikipedia.org/wiki/RAII
创建一个帮助器类,目的是确保在所有执行路径中始终删除一个对象。
这样的类的示例是:std :: auto_ptr
但有时你喜欢与其他人分享对象。它只应在不再使用它时删除。
为了帮助完成该引用,已经开发了计数策略,但您仍需要手动记住addref和release ref。实质上,这与new / delete相同。
这就是为什么boost开发了boost :: shared_ptr,它的引用计数智能指针,这样你就可以无意间共享对象而不会泄漏内存。
随着C ++ tr1的加入,现在它也被添加到c ++标准中,但它名为std :: tr1 :: shared_ptr&lt;&gt;。
如果可能,我建议使用标准共享指针。 ptr_list,ptr_dequeue等是指针类型的IIRC专用容器。我暂时忽略它们。
所以我们可以从你的例子开始:
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
现在的问题是,每当G走出范围我们泄漏添加到G的2个对象。让我们重写它以使用std :: tr1 :: shared_ptr
// Remember to include <memory> for shared_ptr
// First do an alias for std::tr1::shared_ptr<gate> so we don't have to
// type that in every place. Call it gate_ptr. This is what typedef does.
typedef std::tr1::shared_ptr<gate> gate_ptr;
// gate_ptr is now our "smart" pointer. So let's make a vector out of it.
std::vector<gate_ptr> G;
// these smart_ptrs can't be implicitly created from gate* we have to be explicit about it
// gate_ptr (new ANDgate), it's a good thing:
G.push_back(gate_ptr (new ANDgate));
G.push_back(gate_ptr (new ORgate));
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
当G超出范围时,内存会自动回收。
我在团队中困扰新人的练习是要求他们编写自己的智能指针类。然后你完成后立即丢弃课程,再也不用了。希望您获得关于智能指针如何工作的关键知识。真的没有魔力。
答案 3 :(得分:2)
boost文档提供了一个非常好的开始示例: shared_ptr example(它实际上是关于智能指针的矢量)或 shared_ptr doc Johannes Schaub的以下答案很好地解释了提升智能指针: smart pointers explained
背后的想法(尽可能少的话)ptr_vector是它为你处理存储指针后面的内存释放:假设你有一个指针向量,如你的例子所示。当退出应用程序或离开定义向量的范围时,你必须自己清理(你已动态分配ANDgate和ORgate)但只是清除向量将不会这样做因为向量存储指针而不是实际的对象(它不会破坏但它包含的内容)。
// if you just do
G.clear() // will clear the vector but you'll be left with 2 memory leaks
...
// to properly clean the vector and the objects behind it
for (std::vector<gate*>::iterator it = G.begin(); it != G.end(); it++)
{
delete (*it);
}
升压:: ptr_vector&LT;&GT;将为您处理上述事实 - 这意味着它将释放它存储的指针后面的内存。
答案 4 :(得分:2)
通过Boost你可以做到 &GT;
std::vector<boost::any> vecobj;
boost::shared_ptr<string> sharedString1(new string("abcdxyz!"));
boost::shared_ptr<int> sharedint1(new int(10));
vecobj.push_back(sharedString1);
vecobj.push_back(sharedint1);
&GT; 用于在矢量容器中插入不同的对象类型。而对于访问你必须使用any_cast,其工作方式类似于dynamic_cast,希望它能满足您的需求。
答案 5 :(得分:1)
#include <memory>
#include <iostream>
class SharedMemory {
public:
SharedMemory(int* x):_capture(x){}
int* get() { return (_capture.get()); }
protected:
std::shared_ptr<int> _capture;
};
int main(int , char**){
SharedMemory *_obj1= new SharedMemory(new int(10));
SharedMemory *_obj2 = new SharedMemory(*_obj1);
std::cout << " _obj1: " << *_obj1->get() << " _obj2: " << *_obj2->get()
<< std::endl;
delete _obj2;
std::cout << " _obj1: " << *_obj1->get() << std::endl;
delete _obj1;
std::cout << " done " << std::endl;
}
这是一个正在运行的shared_ptr的示例。 _obj2已删除,但指针仍然有效。 输出是, 。/测试 _obj1:10 _obj2:10 _obj2:10 完成了
答案 6 :(得分:0)
将不同对象添加到同一个容器中的最佳方法是使用make_shared,vector和基于范围的循环,您将拥有一个漂亮,干净且可读的&#34;代码!
typedef std::shared_ptr<gate> Ptr
vector<Ptr> myConatiner;
auto andGate = std::make_shared<ANDgate>();
myConatiner.push_back(andGate );
auto orGate= std::make_shared<ORgate>();
myConatiner.push_back(orGate);
for (auto& element : myConatiner)
element->run();