3

Adding objects to vectors vs adding pointers to vectors in c++.

Example:

std::vector<Size> buildings;
Size building(buildingWidth, buildingHeight);
buildings.push_back(building);

VS

std::vector<Size*> buildings;
Size *building = new Size(buildingWidth, buildingHeight);
buildings.push_back(building);

Which one is better in terms of memory/performance?

The first one basically creates an object on the stack and adds it to a vector. So there is one instantiation followed by one copy into the vector.

The second one creates an object on the heap. There is one instantiation, but there is no copy into the vector.

Am I correct?

user2381422
  • 5,645
  • 14
  • 42
  • 56
  • 1
    It's correct, but in the second case you have to explicitly `delete` all the stored objects before the `vector` is destroyed. – Matteo Italia May 29 '13 at 15:00

6 Answers6

4

The two storage techniques serve different purposes.

The first technique is useful with "homogenous" vectors, where you do not need polymorphic behavior, and object slicing is not an issue. You get automated resource management in return: you do not need to worry about the ownership of your objects, because the vector makes a copy. A copy is also made internally every time your vector is resized. This consideration makes the first option less attractive when copying the object is somewhat expensive; you need to profile your code to see if this consideration applies to it.

The second technique puts the responsibility for managing the memory on you: every time you decide to remove an object from your vector of pointers, you need to take the ownership, and eventually delete the object explicitly. You can use smart pointers to address the resource management issue. This technique lets you avoid copying, but the process of accessing elements inside the container becomes slightly more involved.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • A way to mitigate some of the drawbacks of the second option is to store smart pointers instead of plain pointers. – Photon May 29 '13 at 15:22
0

They both usually have relatively similar performance, depending on the object size and copy semantics of the object. With regards to memory leaks and usability, the first way is usually much better.

Photon
  • 3,182
  • 1
  • 15
  • 16
  • Uhm, if the copy constructor of `Size` were expensive they would not have similar performance at all. – Matteo Italia May 29 '13 at 15:01
  • 1
    @MatteoItalia, in this case using a move constructor can be a solution. – awesoon May 29 '13 at 15:02
  • 1
    @soon: Indeed. Or just `emplace`. – syam May 29 '13 at 15:03
  • Also, since the original question gave a specific object, Size, that maps to 2 number elements, it's unlikely to be very heavy. – Photon May 29 '13 at 15:03
  • Yes, copying is simple in my case. I guess then the first option is better. – user2381422 May 29 '13 at 15:05
  • @soon & syam: of course, but it's not always an option (not everyone can already work with a C++11 compiler), and since most of the current code is written in C++03 I think it's important to make this clear to OP. – Matteo Italia May 29 '13 at 15:14
  • @Photon: yes, and that's why I said « *if* the copy constructor *were* expensive»; again, it's just a remark about the general case to keep in mind. – Matteo Italia May 29 '13 at 15:15
0

It really depends on the nature of Size. If the object is big (insofar that the copy constructor has to do a lot of work), then you could consider your pointer idea. However you will have to control the memory yourself and, whatever you do, don't inherit from std::vector as inheriting from the standard containers is not a good idea (for one thing they don't have virtual destructors)!

You could build some copy on write semantics in your Size class (a bit like implementations of std::string).

Or have a default constructor and a swap method for Size (you'll need the default constructor to be used in std::vector anyway). Use the swap method to swap in a new Size object into the position in the vector.

On the basis that "premature optimisation is the root of all evil" (attrib. Tony Hoare), I'd stick with the simplest approach; namely your first idea and see how that goes.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • I find your comment about not inheriting from std containers because of lack of virtual destructors, unconvincing. The absence of virtual destructors limits the design of your inheriting class (for good reasons) but does not exclude inheritance. – Captain Giraffe May 29 '13 at 15:08
  • There are indeed many more reasons - see other SO questions - but I thought I should cite at least one of them. – Bathsheba May 29 '13 at 15:09
  • Thanks for the link. The accepted answer (A good answer IMO) says it is fine, as long as you are clear on the public std::vector base. Any coder should be familiar with the design of the std:: containers, i.e. they are not of OO design. And as such would not do stupid things with a vector base. – Captain Giraffe May 29 '13 at 15:16
0

It really comes down to

  • What operations are going to be performed on that vector
  • How frequently objects will be pushed onto the vector

If you're going to be doing any kind of mutable operation on the vector, then you'd better go with a shared_ptr type.

Ultimately, with any kind of performance-related question, it's best to test it out yourself under the conditions of your application.

Steven Maitlall
  • 777
  • 3
  • 5
0

Why not do this:

std::vector<Size> buildings;
buildings.resize(1);
buildings[0].setSize(buildingWidth, buildingHeight);

This way the constructor is only called once, and you don't have to manage the memory yourself. The only disadvantage I can think of is that the width and height are set twice (once in constructor, once in "setSize"), but I don't think you can get away from that unless you use the std::vector<Size *> approach.

Taylor Brandstetter
  • 3,523
  • 15
  • 24
-1

I think the second approach of using vector of pointers is a better of the two options. Because of two simple reasons

  1. If the objects size are bigger then using vector of objects will add unnecessary copying.
  2. If you are passing the vector of objects as argument to a method and then try to modify any object in the vector then it will not get reflected at all the places.
Apoorva sahay
  • 1,900
  • 3
  • 28
  • 45
  • @DavidO I didn't get anything from your comment. – Apoorva sahay May 29 '13 at 15:19
  • 1
    when you say "better of the two options", you are not acknowledging those reasons that might make the first option better. There are rarely "absolutes". The first option is better for trivial (to construct) objects, and doesn't require any thought for RAII. The second solution requires that thought be given to RAII, and adds a level of indirection, which both contribute to code complexity. There are pros and cons that have to be weighed. "Better" can only be "Better in a given situation". – DavidO May 29 '13 at 15:39