C ++:对象的矢量与指向新对象的向量的矢量?

我正在寻求通过编写示例软件渲染器来提高我的C ++技能。 它将对象组成一个三维空间中的点,并将它们映射到一个二维视口,并为每个视点绘制不同大小的圆。 哪个更好:

class World{
    vector<ObjectBaseClass> object_list;
public:
    void generate(){
        object_list.clear();
        object_list.push_back(DerivedClass1());
        object_list.push_back(DerivedClass2());

要么...

class World{
    vector<ObjectBaseClass*> object_list;
public:
    void generate(){
        object_list.clear();
        object_list.push_back(new DerivedClass1());
        object_list.push_back(new DerivedClass2());

?? 在第二个例子中使用指针来创建新的对象会影响使用向量的点,因为向量在第一个例子中会自动调用DerivedClass析构函数,但不会在第二个例子中调用? 指向使用向量时必需的新对象的指针,因为只要您使用访问方法,它们就自己处理内存管理? 现在让我们说我在世界上有另一种方法:

void drawfrom(Viewport& view){
    for (unsigned int i=0;i<object_list.size();++i){
        object_list.at(i).draw(view);
    }
}

当被调用时,这将为世界列表中的每个对象运行绘制方法。 比方说,我希望派生类能够拥有自己的draw()版本。 为了使用方法选择器( - >),列表是否需要指针?


你不会得到你想要的代码

class World{
    vector<ObjectBaseClass> object_list;
public:
    void generate(){
        object_list.clear();
        object_list.push_back(DerivedClass1());
        object_list.push_back(DerivedClass2());

将要发生的事情称为对象切片。 你将得到一个ObjectBaseClass的向量。

为了使多态性工作你必须使用某种类型的指针。 在boost或其他库中可能会有一些智能指针或引用可用,并使代码比第二个建议的解决方案更安全。


既然你明确表示你想改进你的C ++,我会建议你开始使用Boost。 这可以以三种不同的方式帮助你解决问题:

使用shared_ptr

使用shared_ptr可以像这样声明你的向量:

std::vector< boost::shared_ptr< ObjectBase > > object_list;

并像这样使用它:

typedef std::vector< boost::shared_ptr< ObjectBase > >::iterator ObjectIterator;

for ( ObjectIterator it = object_list.begin(); it != object_list.end(); it++ )
    (*it)->draw(view);

这会给你多态性,并且会像使用普通的指针向量一样使用它,但是shared_ptr会为你做内存管理,当最后一个shared_ptr引用它时被销毁。

关于C ++ 11的注意事项:在C ++ 11中, shared_ptr成为std::shared_ptr标准的一部分,因此此方法不再需要Boost。 但是,除非您真的需要共享所有权,否则建议您使用std::unique_ptr ,它是C ++ 11中新引入的。

使用ptr_vector

使用ptr_vector你可以这样做:

boost::ptr_vector< ObjectBase > object_list;

并像这样使用它:

typedef boost::ptr_vector< ObjectBase >::iterator ObjectIterator;

for ( ObjectIterator it = object_list.begin(); it != object_list.end(); it++ )
    (*it)->draw(view);

这将再次像普通的指针向量一样使用,但这次ptr_vector管理对象的生命周期。 与第一种方法的不同之处在于,这里的对象在矢量被销毁时会被销毁,而在它们上面,如果其他shared_ptr引用它们,它们可能会比容器活得更长。

使用reference_wrapper

使用reference_wrapper你可以这样声明它:

std::vector< boost::reference_wrapper< ObjectBase > > object_list;

然后像这样使用它:

typedef std::vector< boost::reference_wrapper< ObjectBase > >::iterator 
    ObjectIterator;

for ( ObjectIterator it = object_list.begin(); it != object_list.end(); it++ )
    it->draw(view);

请注意,您不必像上述方法那样先取消迭代器的引用。 然而,这只有在你的对象的生命周期在其他地方被管理并且保证比vector长度更长时才有效。

关于C ++ 11的注意事项: reference_wrapper也已在C ++ 11中标准化,现在可用作std::reference_wrapper而不使用Boost。

正如Maciej Hs回答指出的,你的第一种方法会导致对象切片。 一般来说,您可能想在使用容器时查看迭代器。


至于你的第一个问题,通常最好是使用自动分配的对象而不是动态分配的对象(换句话说,不要存储指针),只要对于所讨论的类型来说,复制构造和分配是可能的并且不是非常昂贵。

如果不能复制或分配对象,那么无论如何都不能直接将它们放到std::vector ,所以问题是没有意义的。 如果复制和/或分配操作昂贵(例如对象存储大量数据),那么出于效率原因,您可能需要存储指针。 否则,通常最好不要因为你提到的原因而存储指针(自动释放)

至于你的第二个问题,是的,这是存储指针的另一个有效理由。 动态分派(虚拟方法调用)仅适用于指针和引用(并且不能将引用存储在std::vector )。 如果您需要将多个多态类型的对象存储在同一个向量中,则必须存储指针以避免切片。

链接地址: http://www.djcxy.com/p/5413.html

上一篇: C++: Vector of objects vs. vector of pointers to new objects?

下一篇: Why use pointers?