Jump to content
  • Advertisement
Sign in to follow this  
all_names_taken

Container of objects or container of pointers?

This topic is 3755 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm wondering if I should always use containers of pointers or just plain containers when the objects aren't extremely small. An example case: The object X contains a vector, which is filled with data by the constructor of X, and after that it is left unchanged for the entire lifetime of X, but is read frequently. The exact ratio between creation and read operations varies a lot. Example of using "vector of objects":
class X {
  ...
  std::vector<Foo> v;
};

X::X(some_parameters...) {
  v.resize(n);
  for(int i=0; i<n; ++i) {
    v.push_back(Foo(some_parameters...));
  }
}

const Foo& X::getData(some_parameters...) {
  return v[some_index...];
}
Example of using "vector of pointers":
class X {
  ...
  std::vector<Foo *> v;
};

X::X(some_parameters...) {
  v.resize(n);
  for(int i=0; i<n; ++i) {
    v.push_back(new Foo(some_parameters...));
  }
}

const Foo& X::getData(some_parameters...) {
  return *v[some_index...];
}
The question is whether, in the first case, the compiler will be able to optimize away the copy constructor and destructor (or assignment operator) calls for the object passed to push_back, even if the Foo object has custom-written copy constructor, destructor and assignment operator (then, presumably, we will also save calls to new and delete for each Foo object and so save a lot of performance compared to the 2nd example for ALL cases). Or, will the second way of writing it become faster when the Foo objects get larger and more complex?

Share this post


Link to post
Share on other sites
Advertisement
Well your points are valid and I can't tell you off the top of my head which is faster. Just write a quick timed test.
However, I would use whichever is nicer design wise. I personally use the stack version for small objects, for me only structs, and I use the heap version for larger classes. This way the small objects are used by value and only the pointer of the large ojects is accessed. This prevents the use of the & symbol to acquire an address later on in the code whic makes things nicer IMHO.

Share this post


Link to post
Share on other sites
Quote:
Original post by all_names_taken
The question is whether, in the first case, the compiler will be able to optimize away the copy constructor and destructor (or assignment operator) calls for the object passed to push_back

Why don't you just put
cout << "copy constructor" << endl;

inside of the copy constructor and see for yourself?

Share this post


Link to post
Share on other sites
Hi,

I wouldn t worry too much about the speed of the 2 versions.

The choice also depends on the container type you are using.

For version 1) inserting right into a vector requires you to move the allocated objects fore and back.
On the other hand you could say, using a vector with repeated insertion/deletion is bad practice and should be avoided

Using a list instead only requires the allocation of the iterator type.


I would only use version 2) if you want to pass the addresses of you objects to other objects to store them (e.g.: in a manager class).
Consider smart pointers here to get rid of the deletion code.

If you have to insert or delete objects frequently consider using a list instead.
If your objects are that large that reallocation is expensive(no POD type), then they are complex enough, such that you usually don t need them to be continuously aligned in memory.

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
Quote:
Original post by all_names_taken
The question is whether, in the first case, the compiler will be able to optimize away the copy constructor and destructor (or assignment operator) calls for the object passed to push_back

Why don't you just put
cout << "copy constructor" << endl;

inside of the copy constructor and see for yourself?

That would prove nothing because the language semantics call for the copy constructor to be executed. The compiler can effectively do away with the copy constructor if it's inlined, but the semantics of the program must remain the same.

To the original poster, you should be primarily concerned about the design. Since your class has a copy constructor, you probably intend for the objects to be copied, rather than passed around through pointers. So it makes more sense to have objects in the vector instead of pointers. If you believe there's a performance issue, you should measure it both ways after profiling.

Share this post


Link to post
Share on other sites
Don't forget that the new operator (and your missing delete operator) are very expensive operations. You need to compare the cost of dynamic allocation with the cost of your Foo copy constructor. Also, consider the cost of object constrction -- it may be greater than object copying.

It's also quite possible that the compiler would elide the copy constructor when an object in a vector is constructed in place such as in your code example. That's an implementation-specific detail, but it explicitly allowed by the standard, so it's possible.

Really, there is no answer in the general case. Only direct measurement will give you an answer in a particular case.

Share this post


Link to post
Share on other sites
Quote:
Original post by Bregma
It's also quite possible that the compiler would elide the copy constructor when an object in a vector is constructed in place such as in your code example. That's an implementation-specific detail, but it explicitly allowed by the standard, so it's possible.

The standard allows in-place construction of function arguments instead of creation and copying of a temporary. However, I do not believe that copy construction can be avoided in the vector<>::push_back() function itself, because it's explicitly invoked by a placement new. The standard specifically says that a new expression with an initializer calls the appropriate constructor.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!