std::vector of objects / pointers / smart pointers to pass objects(总线错误:10)?

Posted

技术标签:

【中文标题】std::vector of objects / pointers / smart pointers to pass objects(总线错误:10)?【英文标题】:std::vector of objects / pointers / smart pointers to pass objects (buss error: 10)? 【发布时间】:2013-03-31 16:29:39 【问题描述】:

我想请教一个一般性的建议。下面的代码完全编译并大致代表了我处理的代码的结构。 简而言之,我想将一系列派生自基类(Class1)的对象和一些其他参数从一个地方传递到另一个地方。更准确地说,实现父类的不同子类,收集这些子类的实例并传递参数进行处理。

问题是,您建议使用对象向量还是指针向量?我不介意从C++11 (std::unique_ptr, std::shared_ptr) 中寻找一些新的东西,如果这是出于某种原因更好/更安全/更少的内存泄漏/等等。如果有人可以为这种情况提供有关容器的建议和/或使用C++11 提供示例,我将不胜感激。

p/s/hereUncleBens 说,如果/当抛出异常时,使用指针可能会导致内存泄漏。所以也许我真的应该使用 智能指针 来完成这项任务?这看起来如何?

p/p/s/ 很有趣,当我尝试使用来自 std::vector< Container<d>*> / std::vector< Container<d>> 的那些 Class2 对象时,现实生活中的例子给了我 Bus error: 10。但是,我无法在简单的情况下重现错误...

#include <string>
#include <iostream>
#include <vector>


template<int dim>
class Class1 
   public:

     Class1() ;
    ~Class1() ; 

;

template<int dim>
class Class2 : public Class1<dim>

   public:
     Class2() : 
       Class1<dim>() ; 

 ;

template <int dim>
class Container

  public:
     Container( Class1<dim> & f, int param1) : c1(f), param_(param1) 

  Class1<dim>  & c1;
      int param_;
 ;

 static const int d = 2; 

 int main() 
 
    int p = 1;
    Class2<d> c2;
    std::vector< Container<d> *> p_list;
    std::vector< Container<d> > list;
    
      p_list.push_back ( new Container<d> ( c2,p ) ); 
    
    std::cout<<"from pointers: "<<p_list[0]->param_<<std::endl;

    
      list.push_back( Container<d> ( c2,p ) );
    
    std::cout<<"from objects: "<<list[0].param_<<std::endl;
 

【问题讨论】:

【参考方案1】:

首先,Class1的析构函数应该标记为virtual,否则当派生类(例如Class2)的实例被销毁时,它的析构函数将不会被正确调用。

至于你的问题,使用对象容器的后果是:

容器可能需要复制对象,因此您需要确保有一个复制构造函数(示例中的类获取编译器生成的默认构造函数)。复制对象可能会对性能产生影响,您需要正确定义副本的语义(是深还是浅,即您是创建 class1 对象的新副本,还是仅复制引用)。 您不能有任何多态性,因此您不能将 Container 子类化,然后将基类和子类的实例放在同一个容器中。 根据容器,您的对象将在内存中是连续的(向量就是这种情况),这可以带来性能优势。

如果你使用原始指针的容器,那么容器只需要复制指针(更快),你可以添加包含类型的派生实例。缺点是您必须在使用后手动销毁对象,并且正如您所提到的,这很容易泄漏内存。

shared_ptr 与原始指针有类似的优点/缺点,但关键的好处是 shared_ptr 会在不再引用它时为您销毁对象,这使得您不太可能引入内存泄漏(但它仍然当涉及异常时并非不可能这样做)。

鉴于您将这些对象移交给进一步处理,我会说基于 shared_ptr 的方法是一个不错的选择。在原始指针之上使用共享ptr的后果是:

可能存在性能开销,因为为了线程安全,大多数 shared_ptr 实现需要检查/设置锁(这可能涉及对操作系统的系统调用)。 您仍然可以通过在对象之间引入循环引用来泄漏内存。 您必须使用实现 C++11 的编译器或使用外部库(大多数人使用 boost)。

使用 shared_ptrs 的示例看起来像这样(未经测试)。

#include <string>
#include <iostream>
#include <vector>

template<int dim>
class Class1 
   public:
       Class1() ;
       virtual ~Class1() ; 

;

template<int dim>
class Class2 : public Class1<dim>

    public:
        Class2() : 
        Class1<dim>() ; 

;

template <int dim>
class Container

    public:
       Container( boost::shared_ptr<Class1<dim>> f, int param1) : c1(f), param_(param1) 

       boost::shared_ptr<Class1<dim>> c1;
       int param_;
;

static const int d = 2;

int main() 

    int p = 1;
    boost::shared_ptr<Class1<d>> c2 = boost::make_shared<Class2<d>>();

    std::vector<boost::shared_ptr<Container<d>>> list;
    list.push_back(boost::make_shared<Container<d>>(c2,p));

    std::cout << "from objects: " << list[0]->param_ << std::endl;

总而言之,如果接收容器的代码没有在任何地方存储对它们的引用,并且您不需要多态性,那么对象容器可能就可以了。如果接收容器的代码需要将它们存储在某个地方,和/或您想要多态容器,请使用共享 ptrs。

【讨论】:

非常感谢您的详细回答。将修改我的真实代码以实现共享指针... 注意到您没有在答案中定义 list。我猜是std::vector,或者可能更好boost::shared_ptr&lt; std::vector&lt;....&gt;&gt; 糟糕,是的,我错过了。我已经更新了添加列表声明的答案,它是共享 ptrs 的 std::vector。

以上是关于std::vector of objects / pointers / smart pointers to pass objects(总线错误:10)?的主要内容,如果未能解决你的问题,请参考以下文章

std::vector of OpenCV 点,没有 push_back 方法

在基于范围的 for 循环中从 std::vector<Object> 获取指向 Object 的指针

Cpp_vector_Optimizing the usage of std::vector(vector的优化)

如何使用可用于 Swift 类的 std:vector 制作 Objective-c 类

如何使用 boost std::vector of boost::unordered_map 进行序列化/反序列化

将向量的向量合并为单个向量