Why use one vs the other: `boost::shared_array` VS `boost::shared_ptr<std::vector>`?
Asked Answered
B

2

4

So to deal with large blobs of memory either for an image or similar there are clearly lots of options.

Since I'm a fan of smart pointers and RAII I'm wondering about whether it's smarter to go with :

  • a shared_ptr to a std::vector

or

  • to go with a shared_array pointing to a dynamically allocated array.

What are the conceptual, practical, and performance implications of choosing one vs the other?

Bourn answered 22/7, 2011 at 22:13 Comment(6)
and what's wrong with simply std::vector? when shared_* is used it usually means there is no owner, which is frequently a desing defect.Lo
I need to be able to transfer ownership.Bourn
@Gene Bushuyev: I disagree. At least when I use shared_ptr and friends (or other smart pointer implementations), they are used only when there are multiple simultaneous owners with lifetimes that cannot be determined during compile time. Granted they don't occur often, but they have a legitimate use.Melisamelisande
@Catskul: the way to transfer ownership of a vector is swap(). You should only need shared_ptr<vector<T> > when you're actually using the refcounting, that is when multiple different owners need to access the same vector, and you don't know which one will need it longest.Bennington
@In silico - I didn't say they have no legitimate use, I simply said it's infrequent. In practice I noticed they were often used either due to a defective design (where ownership issues were not correctly addressed), or as a poor substitute for unique_ptr.Lo
@Gene Bushuyev: In that case, I totally agree. :-)Melisamelisande
R
3

It's the same as comparing std::vector vs. C array.

Think about shared_array as a RAII C array. What you get is just automatic memory deallocation. Useful in cases when you deal with 3rd-party code that returns arrays. Theoretically it's faster than std::vector in some edge cases, but much less flexible and less secure.

std::vector is probably the better choice.

Rhebarhee answered 22/7, 2011 at 22:22 Comment(4)
Can you think of any particular reason an array would be any faster than std::vector?Bourn
I can imagine arrays being marginally faster when you know the number of elements in advance, because new[] may not overallocate (at least, not as much as std::vector). Again, the speed benefits are usually marginal.Chimere
std::vector simply wraps an ordinary array, so at least accesses should be as fast as raw arrays when the compiler optimizes the code.Melisamelisande
@Larsmans: completely agreed. @Catskul: to enumerate some other rather farfetched cases: optimization turned off, not inlined vector methods invocation (bad compiler?), improper usage of iterators, overuse of std::vector::erase() etc. It's why I said "theoretically it's faster"Rhebarhee
C
3

shared_ptr to std::vector

  • + allows amortized constant time push_back
  • - introduces an extra level of indirection over std::vector

shared_array

  • + does not introduce an extra level of indirection
  • - does not allow amortized constant time append, unless you implement it yourself, which again would take an extra level of indirection.
Chimere answered 22/7, 2011 at 22:21 Comment(8)
re: shared_ptr to std::vector Won't the extra level of indirection be likely optimized away in most cases as far as performance is concerned?Bourn
@Catskul: an extra level of indirection can't be optimized away in nearly any practical situation. Whether the performance hit is significant is another question entirely. I'd say use shared_array when possible, because it's simple, and shared_ptr to vector when you need to change the length of the array.Chimere
@larsman either might look like (*imageData)[index]. In each case a dereference of imageData happens and then a second dereference happens after the pointer arithmetic for the subscript operator in either case. It seems like they would be equivalent, but also optimizable at least in the case of the first dereference, no?Bourn
@Catskul: shared_array<T> wraps a pointer to T; vector<T> wraps a pointer to T; shared_ptr<vector<T> > wraps a pointer to a pointer to T. With shared_array<T> a, you'd get the i'th element with a[i]; with the shared_ptr solution, you'd get the same with (*a)[i].Chimere
@Catskul: If you were a compiler, how would you optimise out a pointer dereference?Chiromancy
@Tomalak if there were many in a row and I could prove that the underlying pointer would not change in the mean time, do all the operations in a register and write it back after. consider "int foo = 0; int * bar = &foo; int ** borf = &bar; for(int i=0;i<10;++i) ++(**borf);"Bourn
@Catskul: and you're also going to do that optimization for a templated class used across multiple translation units?Chimere
I bench-marked and it turns out that the std::vector was faster than a dynamically allocated array, but probably only because of page_faults. And the shared_ptr and shared_array wrappers made no performance difference for access.Bourn
R
3

It's the same as comparing std::vector vs. C array.

Think about shared_array as a RAII C array. What you get is just automatic memory deallocation. Useful in cases when you deal with 3rd-party code that returns arrays. Theoretically it's faster than std::vector in some edge cases, but much less flexible and less secure.

std::vector is probably the better choice.

Rhebarhee answered 22/7, 2011 at 22:22 Comment(4)
Can you think of any particular reason an array would be any faster than std::vector?Bourn
I can imagine arrays being marginally faster when you know the number of elements in advance, because new[] may not overallocate (at least, not as much as std::vector). Again, the speed benefits are usually marginal.Chimere
std::vector simply wraps an ordinary array, so at least accesses should be as fast as raw arrays when the compiler optimizes the code.Melisamelisande
@Larsmans: completely agreed. @Catskul: to enumerate some other rather farfetched cases: optimization turned off, not inlined vector methods invocation (bad compiler?), improper usage of iterators, overuse of std::vector::erase() etc. It's why I said "theoretically it's faster"Rhebarhee

© 2022 - 2024 — McMap. All rights reserved.