Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Storing Sprites In A Vector?  (Read 11735 times)

0 Members and 2 Guests are viewing this topic.

Robustprogram

  • Newbie
  • *
  • Posts: 10
    • View Profile
Storing Sprites In A Vector?
« on: October 26, 2014, 03:04:41 am »
I am wondering what will happen if I store the actual object into the vector instead of the reference to it. I am also worried about how the object will be handled after I am done with it.

Like doing this
std::vector<Sprite> sprites;
Sprite sprite1;
sprites.push_back(sprite1);
//What will happen to sprite1? Bad memory management?
 

Instead of doing this:
std::vector<*Sprite> sprites;
Sprite sprite1;
sprites.push_back(&sprite1);
 

So I am wondering if there is any problems with this implementation.

Gambit

  • Sr. Member
  • ****
  • Posts: 283
    • View Profile
Re: Storing Sprites In A Vector?
« Reply #1 on: October 26, 2014, 03:12:10 am »
For starters, your pointer-to-sf::Sprite syntax is incorrect (It should be std::vector<sf::Sprite*>) and secondly try it and see. You are storing an object on the stack, not dynamically allocating memory for it so you have virtually no chance of poor memory management. Just make sure that the object doesnt go out of scope by using std::move as opposed to making the vector a global variable. If you are having problems with scope, try this post: http://en.sfml-dev.org/forums/index.php?topic=16616.0

Robustprogram

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Storing Sprites In A Vector?
« Reply #2 on: October 26, 2014, 03:29:45 am »
1. woops :3
2. thank you

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Storing Sprites In A Vector?
« Reply #3 on: October 26, 2014, 11:15:33 am »
Just make sure that the object doesnt go out of scope by using std::move as opposed to making the vector a global variable.

That's...not right.

std::move has nothing to do with the scope of an object.  It merely allows the use of a move instead of a copy because you're asserting you won't need the object anymore in the current scope.  This is completely unnecessary for the simple act of adding sprites to a vector (and probably doesn't do anything since sf::Sprite has no internal memory buffers it could move more efficiently than copy).  It's certainly something a relative newbie like Robustprogram should not (and does not) even have to think about at this stage.

It is true that you should have no globals, though I don't think the initial post implied anything was global.

It almost sounds like you're confusing this with the white square problem, where letting a texture go out of scope causes any sprites using it to get drawn as white squares.  However, this also has nothing to do with move semantics because the solution to that problem is to store the texture at the correct scope (eg, as a class member, rather than a local variable in the class' constructor) so it doesn't get destroyed until the program is done with it.

I am wondering what will happen if I store the actual object into the vector instead of the reference to it. I am also worried about how the object will be handled after I am done with it.

Like doing this
std::vector<Sprite> sprites;
Sprite sprite1;
sprites.push_back(sprite1);
//What will happen to sprite1? Bad memory management?
 
sprite1's destructor will get called at the end of this scope, but push_back() made a copy of it.  Said copy will get destroyed by the vector's destructor, also at the end of this scope.  There is absolutely nothing wrong with this code.

In this particular example you could use emplace_back (C++11) to construct the sprite directly inside the vector and thus skip the copy that push_back makes, but even that is an unnecessary optimization you shouldn't worry about too much.  Shuffling sf::Sprites around is not going to be a bottleneck.

Quote
Instead of doing this:
std::vector<*Sprite> sprites;
Sprite sprite1;
sprites.push_back(&sprite1);
 

So I am wondering if there is any problems with this implementation.
This does almost the same thing as above, except it leaks memory because now the vector's destructor won't be able to clean up the copy of sprite1.

The moral is: never use raw owning pointers in modern C++ without a VERY good reason.  You won't need them.  Also avoid using pointers of all kinds because you won't need any of them very often, and even smart pointers are always going to be more error prone than ordinary stack-based objects.  If your program has no pointers in it, you simply can't make most of the common memory management mistakes.
« Last Edit: October 26, 2014, 11:24:59 am by Ixrec »

Gambit

  • Sr. Member
  • ****
  • Posts: 283
    • View Profile
Re: Storing Sprites In A Vector?
« Reply #4 on: October 26, 2014, 11:26:11 am »
It seems like you missed the entire point of my post. Move semantics arent anything super advanced and will move the ownership of the sprite to the vector. Moving a sprite object into a vector will have the same effect as copying it. In the case of a reference wrapper or pointer, you need to move to stop the sprite going out of scope.

The point is, if Robustprogram is having issues with sprites in his vector, he should try moving them if he isnt copying or moving already.

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Storing Sprites In A Vector?
« Reply #5 on: October 26, 2014, 11:44:27 am »
Quote
It seems like you missed the entire point of my post. Move semantics arent anything super advanced and will move the ownership of the sprite to the vector.

They are "super advanced" in the sense that almost nobody will ever have to work with them directly, unless they're managing memory by hand or implementing standard library classes.  If a class can benefit from move semantics, it's the class owner's job to implement them and then C++ will (for the most part) use it automatically when appropriate.  Just because move semantics are easy to understand conceptually does not mean you should have to worry about them every time you want to use a standard container.

In this example move semantics has nothing to do with ownership.  There is still an sf::Sprite both inside and outside the vector that needs to get destroyed.  If a move happens then maybe one of the destructions will be trivial, but it still has to happen.  Move semantics and ownership only truly interact when smart pointers are involved.

In the case of a reference wrapper or pointer, you need to move to stop the sprite going out of scope.

Again, this is just flat out not true.  std::move does not affect when things go out of scope.  At most it might affect what state the sprite is in when it goes out of scope.

See https://stackoverflow.com/questions/15663539/why-isnt-object-returned-by-stdmove-destroyed-immediately if you don't believe me.

Quote
The point is, if Robustprogram is having issues with sprites in his vector, he should try moving them if he isnt copying or moving already.

No, he should describe what the real issue is.  Move semantics is nothing more than an optimization for types that are slow to copy.  It will not magically fix logic bugs.  It will not prevent memory leaks.  Usually it will either reduce memory usage or do nothing at all.  If he has an actual problem with his program, he needs to explain what the problem is so we can tell him the real solution.

But it sounds like he's just confused about the basic value/pointer/reference semantics of C++ and its standard containers and how those interact with memory management.  If all he wants to know is the "right" way to do that stuff in most cases, then the answer is: construct most objects as ordinary values, pass function parameters as values (if small) or references* (if large), avoid pointers of all kinds (especially raw pointers), and don't worry about any of this copy/move stuff until you run into concrete performance problems.

*Since Robustprogram seemed confused about this in his first post: References and pointers are not the same thing.
« Last Edit: October 26, 2014, 11:53:53 am by Ixrec »

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Storing Sprites In A Vector?
« Reply #6 on: October 26, 2014, 11:47:28 am »
@lxrec : you beat me to it. That was almost exactely the reply I was about to write.  +1

Gambit

  • Sr. Member
  • ****
  • Posts: 283
    • View Profile
Re: Storing Sprites In A Vector?
« Reply #7 on: October 26, 2014, 11:56:03 am »
Hmm ok so move is not needed in every situation ill admit and this situation probably doesnt require a move. However if a type can be moved, and is moved, its scope is pretty much changed. Moving a temporary variable into a vector with a greater scope, will mean that the variable will be valid while the vector has valid scope.

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Storing Sprites In A Vector?
« Reply #8 on: October 26, 2014, 12:01:57 pm »
Hmm ok so move is not needed in every situation ill admit and this situation probably doesnt require a move. However if a type can be moved, and is moved, its scope is pretty much changed. Moving a temporary variable into a vector with a greater scope, will mean that the variable will be valid while the vector has valid scope.

Slightly closer but still not true.

You seem to be under the impression that if I move a Foo into a vector<Foo>, then there is only one Foo in the program instead of two.  This is not the case.  If Foo happens to contain a pointer to some dynamically allocated memory, and Foo's implementer chose to implement move semantics, then there will be only one chunk of dynamically allocated memory in the program instead of two.  But there are still two Foos, and the original Foo still needs to be destructed, even though that destruction is probably now trivial.  The ownership of that dynamically allocated memory has indeed been transferred to the Foo inside the vector, but the ownership of the Foos themselves has not changed at all.  You can interpret that as the chunk of memory changing scope, but it's more accurate to say you moved the memory from one wrapper object at one scope to a different wrapper object at a different scope.  Dynamically allocated memory by itself has no scope (which is why we wrap it in objects that have scope).

tl;dr: With a move (on a class that implements move semantics) there is only one chunk of dynamically allocated memory instead of two, but there are still going to be two classes with pointers (even though one of the pointers is probably nullptr).

P.S. The fact that you're this confused about it kind of proves that it's "super advanced" =)
« Last Edit: October 26, 2014, 12:08:00 pm by Ixrec »

Gambit

  • Sr. Member
  • ****
  • Posts: 283
    • View Profile
Re: Storing Sprites In A Vector?
« Reply #9 on: October 26, 2014, 12:09:07 pm »
The thing is, once a variable has been moved, you can no longer use that variable, so its really not an issue unless you misuse move. While literal ownership does not change (except for smart pointers), move is ultimately a tool for transferring ownership and when you move Foo into the vector, the vector is now the implied parent.
« Last Edit: October 26, 2014, 12:18:24 pm by Gambit »

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Storing Sprites In A Vector?
« Reply #10 on: October 26, 2014, 12:20:15 pm »
The thing is, once a variable has been moved, you can no longer use that variable, so its really not an issue unless you misuse move. While literal ownership does not change, move is ultimately a tool for transferring ownership and when you move Foo into the vector, the vector is now the implied parent.

This is getting pretty close to true.  However, the statement that you can no longer use that variable assumes all classes can/should/do implement move semantics.  Most don't, so you can still use it (even though you probably shouldn't).

Plus, the conceptual "ownership" I think you're referring to is still there even when you copy it, because if you modify sprite1 after the push, the copy of sprite1 in the vector doesn't get that modification, and that's probably a logic error.  So you shouldn't use sprite1 directly once it's in the vector, whether or not it was moved.  The move only changes that "should not" into a "can not".

Again, unless you're doing memory management yourself, all of these distinctions are irrelevant and transparent, because C++ just does the right thing without you having to worry about it.

Incidentally, since this is about vectors, just using emplace is probably better than either a copy or a move, because then you just construct the object in the right place to begin with and nothing has to get copied or moved at all.  Notice no std::moves or &&s or pointers or any other esoterica are involved in using emplace.

P.S. Just to be super thorough, I do know of one way in which move semantics does affect how newbies should write code: It is now okay for them to return STL containers by value.  Before that would be an expensive copy, but now C++ will be smart and automatically move it instead.  Once again, notice the newbie does not have to actually use std::move or && anywhere in order to get this benefit, and the old "output parameter" style is still fine if that's what they're used to.



@Robustprogram: Sorry if we horribly confused you by making this thread far more complicated than it needs to be.  I believe my first post contained the actual, correct answer to your original question, but feel free to ask more if you're still unsure.
« Last Edit: October 26, 2014, 12:26:10 pm by Ixrec »

Gambit

  • Sr. Member
  • ****
  • Posts: 283
    • View Profile
Re: Storing Sprites In A Vector?
« Reply #11 on: October 26, 2014, 12:26:11 pm »
Whether or not you can/should move (disregarding the class' implementation) depends on the type the vector holds and what type you are trying to store in it. Its true that for the purpose of this thread, a copy is fine, but if it was a reference or a smart pointer, then move has to be considered (That or refactoring).

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: Storing Sprites In A Vector?
« Reply #12 on: October 26, 2014, 12:32:02 pm »
If smart pointers are involved, then yes, now you're absolutely correct.

If by "references" you mean raw pointers, then also correct.  But actual references can't be copied at all, you can't even have a vector of references, etc.  So let's try not to misuse that term anymore.

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Storing Sprites In A Vector?
« Reply #13 on: October 26, 2014, 12:32:26 pm »
Regarding returning containers by value; even in C++03 code this is usually just fine since the RVO (Return Value Optimization) or NRVO (Named Return Value Optimization) rules will kick in and elide the copy anyway. Explicitly using std::move when returning a value can actually be a pessimization and should generally be avoided. Just return by value.

Dienes

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
AW: Re: Storing Sprites In A Vector?
« Reply #14 on: October 26, 2014, 01:08:23 pm »


If by "references" you mean raw pointers, then also correct.  But actual references can't be copied at all, you can't even have a vector of references, etc.  So let's try not to misuse that term anymore.

He was talking about reference_wrapper before, so I guess that's what he meant. Although references (including reference_wrapper) never have ownership, so it's still irrelevant to talk about moving them.