3

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

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

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

p/p/s/ 很有趣,现实生活中的例子给了我Bus error: 10 when I try to use those Class2objects from std::vector< Container<d>*> / std::vector< Container<d>>. 但是,我无法在简单的情况下重现该错误...

#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;
 }
4

1 回答 1

0

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

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

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

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

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

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

  • 可能会有性能开销,因为为了线程安全,大多数 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。

于 2013-03-31T17:29:33.800 回答