3

I would like to ask a general advise. The code below fully compiles and roughly represents the structure of the code i deal with. In a nutshell i want to pass a series of objects derived from the based class (Class1) and some other parameters from one place to another. More precisely, implement different child classes of the parent class, gather instances of those and pass for processing with parameters.

The question is, would you recommend to use a vector of objects or vector of pointers? I don't mind going for some new stuff from C++11 (std::unique_ptr, std::shared_ptr) if this is better/safer/less memory leaks/etc for some reason. I would really appreciate if someone could arguably advise on container for such a case and/or provide an example using C++11.

p/s/ here UncleBens said that using pointers could lead to memory leaks if/when exceptions are thrown. So maybe i should really use smart pointers for the task? How would this look?

p/p/s/ funny enough, the real life example gives me Bus error: 10 when i try to use those Class2 objects from std::vector< Container<d>*> / std::vector< Container<d>> . However, i'm not able to reproduce the error in a simple case...

#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;
 }
Community
  • 1
  • 1
Denis
  • 1,526
  • 6
  • 24
  • 40

1 Answers1

0

Firstly, the destructor of Class1 should be marked virtual, otherwise when an instance of a deriving class (Class2 for example) is destroyed, it's destructor wont be called correctly.

As for your question, the consequences of using a container of objects are:

  • The container might need to make copies of the objects, so you need to make sure there is a copy constructor (your class in the example gets the default one generated by the compiler). Copying objects can have a performance impact, and you need to properly define the semantics of the copy (is it deep or shallow, i.e. do you create a new copy of the class1 object, or just copy the reference).
  • You can't have any polymorphism, so you couldn't subclass Container and then put instances of the base and subclass in the same container.
  • Depending on the container, your objects will be contiguous in memory (this is the case for a vector) which can have performance benefits.

If you use a container of raw pointers, then the container only needs to copy pointers (faster) and you can add derived instances of the contained type. The downside is that you'll have to destroy the objects manually after use and as you mentioned, it's easy to leak memory.

shared_ptrs have similar benefits/downsides to raw pointers, but the key benefit is the the shared_ptr destroys the object for you when nothing is referencing it any more, this makes it less likely that you'll introduce memory leaks (but it's still not impossible to do so when exceptions are involved).

Given that your handing these objects over for further processing, I would say a shared_ptr based approach is a good option. The consequences of using shared ptrs over and above those of raw pointers are:

  • There can be a performance overhead, as in order to be thread safe, most shared_ptr implementations need to check/set locks (this might involve a system call to the OS).
  • you can still leak memory by introducing circular references between objects.
  • you'll have to use a compiler implementing C++11 or use external libraries (most people use boost).

An example using shared_ptrs would look something like this (not tested).

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

In summary, if the code receiving the containers doesn't store refs to them anywhere, and you don't need polymorphism, then a container of objects is probably ok. If it is necessary for the code receiving the containers to store them somewhere, and/or you want polymorphic containers, use shared ptrs.

JS.
  • 616
  • 4
  • 13
  • thanks a lot for a detailed answer. Will be reworking my real-life code towards shared pointers... – Denis Mar 31 '13 at 17:47
  • noticed that you didn't define `list` in your answer. I guess it's `std::vector`, or probably better `boost::shared_ptr< std::vector<....>>` ? – Denis Apr 02 '13 at 09:07
  • Oops, yes I missed that. I've updated the answer to add the declaration of list, it's an std::vector of shared ptrs. – JS. Apr 03 '13 at 21:35