SFML community forums

Help => Graphics => Topic started by: RetroX on March 07, 2010, 03:36:22 am

Title: Creating std::vector of sf::Image/Sound
Post by: RetroX on March 07, 2010, 03:36:22 am
This is probably a frowned-upon method of doing things.

Would it be considered "safe" to create an std::vector of sf::Image, to act as an array?  I use it as a way to store dynamically-sized arrays of loaded images, but after reading the tutorial, it warns on Image-loading and the like, and I'd like to just ask for a general opinion.  It hasn't caused any problems on my new box (3.4GHz x4, 4GB, Arch Linux/Win7) or my old box (1.2GHz x1, 512MB, Arch Linux/Win2k).

For example, the following code:
Code: [Select]
std::vector<sf::Image> array;
array.resize(2);
if (!array[0].LoadFromFile("image.png") || !array[1].LoadFromFile("image2.png"))
 {
 exit(EXIT_FAILURE);
 }

(obviously, in this case, you'd just use sf::Image array[2], but as a concept)

I have no idea how std::vector or sf::Image work, so, I figured that I'd ask this.
Title: Creating std::vector of sf::Image/Sound
Post by: model76 on March 07, 2010, 05:24:48 am
For your question about std::vector vs. array, vectors are usually preferred, because they can do anything an array can do, and more.
Once you get into vectors, you are going to love them! :)

Actually, I can't even remember the last time I used an array. I simply just can't find a good reason to use them.

Also, when you have learned about vectors, you will want to look into iterators, too, and then later, the other STL containers. A whole world of possibilities will open up for you.

Happy learning! :)
Title: Creating std::vector of sf::Image/Sound
Post by: Walker on March 07, 2010, 05:38:12 am
I don't think there is any issue with your example. I think the problems the tutorial mentions come when you copy images.

I just had a skim through the image/sprite tutorial and it even mentions (at the end) that you can use an "image manager", which sounds similar to what you are doing.

Vectors are pretty awesome :)
Title: Creating std::vector of sf::Image/Sound
Post by: Laurent on March 07, 2010, 09:56:53 am
Quote
Would it be considered "safe" to create an std::vector of sf::Image, to act as an array?

Absolutely. The only thing that you must keep in mind is that some operations (such as adding an element) may move all the vector elements elsewhere in memory, invalidating all the sprites that previously pointed to them.

Quote
Actually, I can't even remember the last time I used an array. I simply just can't find a good reason to use them.

Using a vector everywhere is a mistake, if your array is not dynamic then just use a raw array (or boost.array) ;)
Title: Creating std::vector of sf::Image/Sound
Post by: Nexus on March 07, 2010, 12:45:22 pm
Probably, std::list is the better choice here. It has two big advantages: Adding an element always takes constant time, while vectors might reallocate their whole sequence, unnecessarily copying thousands of pixels. The second pro is that iterators, references and pointers to the elements of std::list remain valid. You probably don't need random access, and the small node overhead of the doubly linked list is negligible compared to the memory required by sf::Image.

However, if your container has a constant size which is known at compile time, then I'll recommend std::tr1::array. This class behaves like a raw array, except that it's more comfortable and secure in debug-mode.
Title: Creating std::vector of sf::Image/Sound
Post by: RetroX on March 07, 2010, 06:59:56 pm
The main reason that I asked was because of std::vector's capacity allocation; I wasn't sure if in doing that, it would create tons of unused images, taking up a load of memory.

Anyways, thanks for the help.  I'll look into seeing if std::list is a better solution, as well.
Title: Creating std::vector of sf::Image/Sound
Post by: Laurent on March 07, 2010, 07:11:45 pm
Quote
The main reason that I asked was because of std::vector's capacity allocation; I wasn't sure if in doing that, it would create tons of unused images, taking up a load of memory.

std::vector allocates more memory than what is necessary to store the elements, but it's unused memory, no dummy instance is created.
Title: Creating std::vector of sf::Image/Sound
Post by: OniLinkPlus on March 07, 2010, 07:25:52 pm
Another way you could go about doing this is use a std::map where the key is the filename, in order to write an efficient image manager, but I am not sure if it pulls a std::vector and moves the entire array occasionally on the addition of a new element, or if it goes the double-linked list route.
Title: Creating std::vector of sf::Image/Sound
Post by: Nexus on March 07, 2010, 10:39:50 pm
Quote from: "OniLink10"
I am not sure if it pulls a std::vector and moves the entire array occasionally on the addition of a new element, or if it goes the double-linked list route.
Neither of them. std::map arranges its elements in a tree structure. Like at std::list, Iterators remain valid and the single elements are not copied when the map grows. In contrast, access, insertions and removals have a complexity of O(log(n)).
Title: Creating std::vector of sf::Image/Sound
Post by: model76 on March 07, 2010, 10:52:54 pm
Quote from: "Laurent"
Quote
Would it be considered "safe" to create an std::vector of sf::Image, to act as an array?

Absolutely. The only thing that you must keep in mind is that some operations (such as adding an element) may move all the vector elements elsewhere in memory, invalidating all the sprites that previously pointed to them.
That certainly is an important point, that I had not thought about... Thanks for making it clear!

Quote from: "Laurent"
Quote
Actually, I can't even remember the last time I used an array. I simply just can't find a good reason to use them.

Using a vector everywhere is a mistake, if your array is not dynamic then just use a raw array (or boost.array) ;)
Why is that a mistake? Vectors make iterating over the entire array much simpler, for instance, as it knows about its size. Is it wrong to use a vector as a safer array, with more features?
Title: Creating std::vector of sf::Image/Sound
Post by: Laurent on March 07, 2010, 11:12:41 pm
Quote
Why is that a mistake? Vectors make iterating over the entire array much simpler, for instance, as it knows about its size. Is it wrong to use a vector as a safer array, with more features?

I'm not talking about raw dynamic arrays, which should indeed never be used, I'm talking about static arrays. If you want 10 ints then use a int[10] (or a boost::array<int, 10>), not a std::vector<int>.
Title: Creating std::vector of sf::Image/Sound
Post by: model76 on March 07, 2010, 11:16:40 pm
Quote from: "Laurent"
Quote
Why is that a mistake? Vectors make iterating over the entire array much simpler, for instance, as it knows about its size. Is it wrong to use a vector as a safer array, with more features?

I'm not talking about raw dynamic arrays, which should indeed never be used, I'm talking about static arrays. If you want 10 ints then use a int[10] (or a boost::array<int, 10>), not a std::vector<int>.
Sure, I understand that, but why is vector not good for that? I am just trying to get smarter :)
Title: Creating std::vector of sf::Image/Sound
Post by: Nexus on March 07, 2010, 11:18:34 pm
Quote from: "model76"
Why is that a mistake? Vectors make iterating over the entire array much simpler, for instance, as it knows about its size. Is it wrong to use a vector as a safer array, with more features?
It's always wrong to use something everywhere just because it has some advantages. Never stop thinking. ;)

An array with automatic storage (such as T[size] or std::tr1::array<T, size>) fits better when 1. the size is constant and known at compile time and 2. you need a very fast memory allocation. In contrast, the std::vector<T> comes with overhead you don't need.

However, I would still prefer std::tr1::array over raw arrays because this class has a STL-compatible interface with methods such as begin(), end() or size(). Additionally, a useful implementation places assertions in debug-mode so that errors like out-of-ranges are caught. And on modern compilers, there's no reason why the class should be slower.
Title: Creating std::vector of sf::Image/Sound
Post by: Laurent on March 07, 2010, 11:21:05 pm
Quote
Sure, I understand that, but why is vector not good for that?

Why do you think it is good for that?
Title: Creating std::vector of sf::Image/Sound
Post by: model76 on March 08, 2010, 12:37:46 am
Nexus -> Nice thorough, comprehensible explanation - Thanks! :)
It still leaves me thinking that std::vector is the best solution in most cases, though, provided that we stick to current standard C++. If we include boost and non-standard extensions, such as tr1, sure, there are probably better solutions. But I don't use those (yet), and I am guessing the original poster doesn't either.

Laurent -> I already gave you an example of that, and if you look at the last paragraph in Nexus' post, you can find even more reasons. You, however, have not stated one single reason why an olden timey array would be better for anything. :shock:
Luckily, Nexus was kind enough to do so, so don't worry about it. :)
Title: Creating std::vector of sf::Image/Sound
Post by: Laurent on March 08, 2010, 09:06:12 am
Quote
Laurent -> I already gave you an example of that, and if you look at the last paragraph in Nexus' post, you can find even more reasons. You, however, have not stated one single reason why an olden timey array would be better for anything. :shock:
Luckily, Nexus was kind enough to do so, so don't worry about it. :)

Sorry, I didn't mean to be unsympathetic.
I gave you that answer on purpose, I wanted to reach the same conclusion as Nexus that there's nothing in std::vector that you need for static arrays, and that all this "cool extra stuff" that you get is in fact unnecessary overhead. The best solution is to use something that adds stuff on top of static arrays, like boost::array or std::tr1::array, not to use dynamic arrays.

Sometimes I answer to people with dumb questions to make them think and then show them why they're wrong, rather than writing the big, thorough comprehensible explanation (english is not my mother tongue and it takes me more time to write long answers -- it took me 30 min to write this one :lol:).
Title: Creating std::vector of sf::Image/Sound
Post by: model76 on March 08, 2010, 11:25:19 pm
That's OK, you are forgiven ;) But I really had already thought about it..

I understand about the language barrier, as English isn't native to me, either. In fact, http://www.tfd.com/ is probably in the top 5 of my most visited sites, even tough I consider myself to be pretty good at English...


To get back on topic, I still feel that a vector is a good choice, in most cases, even if you don't necessarily need a dynamic array (still assuming that we stick to standard C++).
The only cases I can think of, where it would not make sense, is if

1) You just need it to hold data, that you don't ever intend on accessing, after initialization (or maybe if you plan to access it with an enum).

Or 2) The extra overhead of the vector gets in the way of the workings of your program (you need the array for optimization).

If you ever need to simply loop through the array, or pass it to a function, the size method, safety, and nice STL interface should be worth the extra bit of overhead, or what?
And if you know the size at compile time, then it is really easy to tell the vector to preallocate the memory it will need, so that should take care of at least some of the overhead.

So maybe I am wrong. Maybe my cost/benefit analysis is off, due to lack of experience, but I still haven't heard a good argument for not using vector by default, except for a few special cases.
So if there truly is one, I will be most happy to hear it, since I am always interested in correcting bad habits. :)
Title: Creating std::vector of sf::Image/Sound
Post by: Nexus on March 09, 2010, 12:53:54 am
Quote from: "model76"
If you ever need to simply loop through the array, or pass it to a function, the size method, safety, and nice STL interface should be worth the extra bit of overhead, or what?
What if all of the mentioned features would come without any overhead? I.e. take all the advantages and pay nothing? Sound like a good deal, doesn't it? ;)

That's exactly where std::tr1::array comes into play. You should have a look at it (or at boost::array, which is actually the same). Of course, raw arrays can't be directly compared to std::vector, even though they support iterators.
Title: Creating std::vector of sf::Image/Sound
Post by: model76 on March 09, 2010, 10:59:41 pm
Sure, that would be very nice, but tr1 is not standard, and boost is a huge, complicated external library. In my opinion, that is, quite frankly, not very good advice for someone who is just getting ready to get their feet wet with STL containers, and maybe feeling a bit anxious about it.
That is how I read the opening post.

ahem, I realize now that this might not have been aimed at the original poster, but directly at me, in which case you are right. It is about time I finally take another crack at unlocking the mystery that is boost.
But as it happens, someone once suggested boost to me, when I was clearly not ready. That lead to many hours of frustration and reading of technical manuals, that I had zero chance of understanding. So I have been somewhat reluctant to go back on that path, you see.

I will look into it as soon as my current project is done. Thank you for reminding me! :)
Title: Creating std::vector of sf::Image/Sound
Post by: Nexus on March 09, 2010, 11:06:41 pm
Quote from: "model76"
but tr1 is not standard
But it's an official extension to C++98 that has already existed seven years. All modern standard library implementations support TR1.

Quote from: "model76"
It is about time I finally take another crack at unlocking the mystery that is boost.
Yes, Boost is a great library and offers very interesting concepts. Even though I don't like all implementations (some of them tend to be overengineered), many libraries make daily work a lot easier (for example Bind, SmartPtr or PointerContainer).
Title: Creating std::vector of sf::Image/Sound
Post by: model76 on March 09, 2010, 11:13:27 pm
Quote from: "Nexus"
But it's an official extension to C++98 that has existed already seven years. All modern standard library implementations support TR1.
Really? I had no idea! I thought it was just a kind of preview of what the next installment of C++ has to offer, that compiler vendors could implement at their own leisure. That's a whole new set of toys to play with, so thanks for pointing that out!
Title: Creating std::vector of sf::Image/Sound
Post by: Nexus on March 09, 2010, 11:19:19 pm
No problem. :)

If you use Microsoft Visual Studio, you can include std::tr1::array from <array>, G++ uses <tr1/array>. I don't know about other compilers...

By the way, Bind and Function are also in TR1, as well as Unordered Map/Set or Random Number Generators. I especially like std::tr1::bind and std::tr1::function. ;)
Title: Creating std::vector of sf::Image/Sound
Post by: Laurent on March 09, 2010, 11:21:24 pm
If all you need is begin(), end() and size(), then they can easily be implemented from scratch for static arrays
Code: [Select]
template <typename T, std::size_t N>
std::size_t size(T(&)[N])
{
    return N;
}

template <typename T, std::size_t N>
T* begin(T(&array)[N])
{
    return &array[0];
}

template <typename T, std::size_t N>
T* end(T(&array)[N])
{
    return begin(array) + N;
}


You can even write your own minimal version of tr1/boost array, it's just a matter of minutes.
Title: Creating std::vector of sf::Image/Sound
Post by: Nexus on March 09, 2010, 11:31:12 pm
Quote from: "Laurent"
You can even write your own minimal version of tr1/boost array, it's just a matter of minutes.
That's true, but it's nothing compared to a fully tested and optimized container class (ok, the case here is not too complex since tr1::array is a rather thin wrapper, but anyway). What I really like at the MSVC++ implementation are the debug assertions and checked iterators. Such features depend on one's needs, I'm glad I don't have to abandon them... ;)
Title: Creating std::vector of sf::Image/Sound
Post by: Laurent on March 09, 2010, 11:34:46 pm
I know, I was just trying to provide an alternative that would still be better than std::vector, for those who want a standard/portable solution without using boost ;)
Title: Creating std::vector of sf::Image/Sound
Post by: asdatapel on October 22, 2011, 02:27:27 am
Quote
Absolutely. The only thing that you must keep in mind is that some operations (such as adding an element) may move all the vector elements elsewhere in memory, invalidating all the sprites that previously pointed to them.


Okay, so I have an object that has a Image member and a Sprite member.
I create one of those objects, change a few options, and push it into a an vector, change a few options, push it into a vector, repeating until I have enough.The sprites that I draw all turn white. Is it because of what you're talking about?, and if so, how do I fix it?
Title: Creating std::vector of sf::Image/Sound
Post by: Nexus on October 22, 2011, 12:50:38 pm
Please don't revive old threads.

You must be sure that the sprite's pointer refer to valid images. So call SetImage() at last, or use containers like boost::ptr_vector or std::list that don't invalidate their element references.