Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Smart Pointers in a Vector container

I wrote the classic Shape Polymorphism code, but a little bit different because I'm using a Vector container and smart pointers.

I am not a C++ expert, and I would like to know the following:

  1. Is there any memory leak?
  2. If I don't call shapes.clear(), is there going to be a memory leak?
  3. Is there a better way to use smart pointers and containers?

Code:

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

class Shape {
  public:
    virtual float getArea() = 0;
    virtual ~Shape() {}
};

class Rectangle : public Shape {
  public:
    Rectangle(float w, float h) : width(w), height(h) {}

    float getArea() {
      return width * height;
    }
  private:
    float width;
    float height;
};

class Circle : public Shape {
  public:
    Circle(float r) : radius(r) {}

    float getArea() {
      return 3.141592653589793238462643383279502884 * radius * radius;
    }
  private:
    float radius;
};

void printShapeAreas(vector<shared_ptr<Shape>> &shapes) {
  for(int i = 0; i < shapes.size(); i++) {
    cout << shapes[i]->getArea() << endl;
  }
}

int main(int argc, char** argv) {
  vector<shared_ptr<Shape>> shapes;
  //this works, but you told me that is better to use make_shared
  //=============================================================
  //shapes.push_back(shared_ptr<Shape>(new Rectangle(10, 2)));
  //shapes.push_back(shared_ptr<Shape>(new Rectangle(10, 3)));
  //shapes.push_back(shared_ptr<Shape>(new Circle(2)));
  //shapes.push_back(shared_ptr<Shape>(new Circle(3)));
  //better
  //======
  shapes.push_back(std::make_shared<Rectangle>(10, 2));
  shapes.push_back(std::make_shared<Rectangle>(10, 3));
  shapes.push_back(std::make_shared<Circle>(2));
  shapes.push_back(std::make_shared<Circle>(3));
  printShapeAreas(shapes);
  shapes.clear();//If I don't call shapes.clear(), is there going to be a memory leak?
  return 0;
}

Thank you :)

like image 210
Emmanuel Lozoya Avatar asked Mar 30 '16 22:03

Emmanuel Lozoya


People also ask

How do you store pointers in vector?

You can store pointers in a vector just like you would anything else. Declare a vector of pointers like this: vector<MyClass*> vec; The important thing to remember is that a vector stores values without regard for what those values represent.

Why auto_ptr Cannot be used with STL?

If we copy the auto_ptr then the source auto_ptr will lose the reference to the underlying object. Since objects within an STL container must be copy-constructible and assignable, a compile time error is provided if an auto_ptr is used within a container.

Are smart pointers on the stack or heap?

As shown in the example, a smart pointer is a class template that you declare on the stack, and initialize by using a raw pointer that points to a heap-allocated object.

Do you need destructors with smart pointers?

Boost smart pointers by themselves don't have anything to do with the need for a destructor. All they do is remove the need for you to call delete on the allocated memory that they are effectively managing.


2 Answers

Your code doesn't contain a memory leak. So your first point is fine.

No, if you don't call shapes.clear(), there will not be a memory leak since std::vector's destructor cleans up the container.

I don't know a specific rule about using shared pointers in a container so I'll skip on your third question.

However, I can offer an improvement for creating std::shared_ptrs:

When you create a shared pointer using its constructor, ie shared_ptr<T>(new T());, the control block or the structure that holds bookkeeping information about that resource, is created separately from the object it points to. This might cause cache misses a lot. However, if you create a shared_ptr by using std::make_shared, the control block is allocated with the object you want, therefore, by keeping them together, you can at least mitigate the cost of cache misses: std::make_shared<T>();. For example: std::make_shared<Circle>(3) is equivalent to writing std::shared_ptr<Shape>(new Circle(3)), but usually better.

like image 66
Fatih BAKIR Avatar answered Nov 15 '22 07:11

Fatih BAKIR


1) I don't see a memory leak here. However there is a potential to getting one sooner or later: your shape destructor is not virtual. This means that shapes are always destroyed using the base destructor, instead of the right destructor. I.e. if one of your derived shapes would one day allocate memory, it's destructor that would have to release it wouldn't be called.

2) Nothing will happen: if you don't do a clear(), shapes will get destroyed anyway when main() is left, causing its contend to get destroyed.

3) Maybe, but this one is already very good.

like image 29
Christophe Avatar answered Nov 15 '22 09:11

Christophe