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

Author Topic: sf::Sprite/Texture(/Image) and pointers  (Read 7147 times)

0 Members and 1 Guest are viewing this topic.

GetOutOfBox

  • Newbie
  • *
  • Posts: 8
    • View Profile
sf::Sprite/Texture(/Image) and pointers
« on: July 09, 2012, 04:22:28 am »
I'm a new user of SFML, and so far I'm really enjoying it. However, I'm having a bit of a problem understanding how SFML objects (particularly Graphics objects) work when you're creating them on the heap, and then passing them around as pointers. If I need to pass a sf::Texture to an sf::Sprite, if I'm passing a pointer to it (as I have to when it's on the heap, of course), I'm forced to dereference it first. My question regarding this is, will dereferencing a pointer to an SFML object, as an argument to another (see example to clarify what I mean), result in a copy of the first being made?

For example:

sf::Texture* texture;
sf::Sprite* sprite;

texture = new sf::Texture;
sprite = new sf::Sprite;

sprite->setTexture(*texture);

Is there a better way to pass SFML objects on the heap around, rather than dereferencing them all the time (which sounds like terrible design on my part)? Furthermore, do SFML top-level objects (i.e sf::Sprite, sf::Sound) store most of their data on the heap already (and hence it should be fine to store the objects themselves on the stack)? I know things like sf::Texture store pixel data in video memory, but say I'm juggling 50 sprites, would it make sense to put them on the heap? Or are they lightweight enough to go on the stack?

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: sf::Sprite/Texture(/Image) and pointers
« Reply #1 on: July 09, 2012, 05:22:52 am »
No offense, but your assumptions about where variables are stored based on their declarations is false. Declaring a complete non-pointer object as a member of a class will not guarantee that that object is never put on the heap. If the encompassing class is put on the heap all it's members will be put there too. If it is put on the stack it's members will be put on the stack as well. The important part is that only it's members will be put on the stack, the data that those members point to (if they are pointers) exists on the heap. You should never make use of pointers to stack data, that is unhealthy.

When you pass data structures around when calling functions there are 2 main ways to do it, call by value and call by reference. To use call by value you have a function signature that takes a simple non-reference value and every time that function is called, it's arguments are copied onto the stack of that function for it to make use of within it's scope. To make use of call by reference you have a function signature that takes a reference to one of your variables and can even alter that variable if it was not passed as a const reference. Those variables are not copied and thus do not exist on the stack of the callee. This is simply put like a pointer with automatic dereferencing. When passing a pointer, most of the time you are making use of call by value (I have yet to see a pointer reference being passed around) because the pointer really is a value that exists as part of the object it is part of or as a local variable in the scope of the function it was created in.

It really doesn't make sense to pass SFML resources around using pointers. Most of it's interface makes use of const references already and are thus as efficient as pointers without the unneeded clutter. Deeper down, at the interface to the underlying libraries that make SFML work, the raw resources are always stored on the heap. This begins already at any STL container that is used. All STL containers have to store their resources on the heap due to having a dynamic size.

From a user perspective SFML objects are more like handles to the low-level objects. Shallow copying an SFML object would not change anything about the resource it is in charge of.

Unless you have some thought out resource management system, the simplest solution would be to have each object in your game hold the SFML objects it makes use of as values. This means that those objects own their resources exclusively. If you want shared ownership semantics you would need to go a bit further.

Long story short, unless you only make use of arrays, don't use new/delete and don't use STL containers and most of the other language utilities of C++ you can be sure most of your data is ending up on the heap, even if you don't want it to. Use raw pointers as little as possible. They are the most common error source in any C++/C programmers life and the reason why smart pointers are part of C++11.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

GetOutOfBox

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: sf::Sprite/Texture(/Image) and pointers
« Reply #2 on: July 09, 2012, 06:07:46 am »
As a rule of thumb, when using tons of objects, it's best to place them on the heap, as the stack has a fairly limited size. In this particular case, I have a game with a tile engine, which not only caches the tiles on the "screen" in memory, it caches the entire map as well. As such, there could easily be 10 000 tiles or more in use at once, just to host a 100*100 tile map.

I require the use of pointers. The way my tile engine works (there's a vector of tiles (pointers) representing what's on the screen, upon which the player walks, and a seperate vector containing all of the tiles (pointers) in the map, the ones surrounding the player are copied to the screen vector), due to this design, it's much simpler to simply use a vector of pointers, which are deleted when the screen changes and replaced using a copy constructor (overloaded to perform a deep-copy) built into the Tile class. Perhaps this is not the best design, but I'm purposely trying to go through the evolution of my engine in order to teach myself, rather than just have someone tell me the best way to do it. Either way, that's outside the scope of this thread.

I realize that using "new" is asking for trouble down the line, and I do plan to replace manual allocation with boost::shared_ptr's later on. However, I'm not having heap issues atm (thanks Valgrind :) ), and I'm still early in development, so I'd rather save that for later.

How about I put it this way (and perhaps I'm still not fully understanding dereferencing), but when you dereference a pointer, is the copy constructor for the object called, and a copy made?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: sf::Sprite/Texture(/Image) and pointers
« Reply #3 on: July 09, 2012, 11:25:45 am »
First, dont use new and delete. Especially with the availability of STL containers and the C++11 std::unique_ptr, manual memory management makes code unnecessarily complicated and error-prone. Have a look at the RAII idiom. And don't use std::shared_ptr unless you really need shared ownership, because it has quite a big runtime overhead.

Second, the dereferencing operator just returns a reference to the pointee object, no copy is performed.
« Last Edit: July 09, 2012, 07:53:01 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Haze

  • Full Member
  • ***
  • Posts: 201
    • View Profile
    • Github Profile
Re: sf::Sprite/Texture(/Image) and pointers
« Reply #4 on: July 09, 2012, 11:36:55 am »
when you dereference a pointer, is the copy constructor for the object called, and a copy made?
Copying objects and dereferencing pointers are two different and independent operations, the copy constructor is simply called when you proceed to copy an object.
sf::Texture* t1 = new sf::Texture();

sf::Texture& t2 = *t1; // no copy, using a reference
sf::Texture  t3 = *t1; // copy constructor called
 

In your case, sf::Sprite::setTexture takes a reference (const sf::Texture&), so no copy is done here.

GetOutOfBox

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: sf::Sprite/Texture(/Image) and pointers
« Reply #5 on: July 09, 2012, 09:11:30 pm »
First, dont use new and delete. Especially with the availability of STL containers and the C++11 std::unique_ptr, manual memory management makes code unnecessarily complicated and error-prone. Have a look at the RAII idiom. And don't use std::shared_ptr unless you really need shared ownership, because it has quite a big runtime overhead.

Second, the dereferencing operator just returns a reference to the pointee object, no copy is performed.

As I've already said, I am aware of the dangers of using new/delete, and do plan to replace them with smart pointers later. They are however useful placeholders, as I know there are no heap problems right now.

Copying objects and dereferencing pointers are two different and independent operations, the copy constructor is simply called when you proceed to copy an object.
sf::Texture* t1 = new sf::Texture();

sf::Texture& t2 = *t1; // no copy, using a reference
sf::Texture  t3 = *t1; // copy constructor called
 

In your case, sf::Sprite::setTexture takes a reference (const sf::Texture&), so no copy is done here.

Alright, so no copy is made when dereferencing to a reference. Why is that though? Isn't there only two ways to pass data, by reference or by value? According to Wikipedia, dereferencing passes an equivalent l-value, so in my mind, unless that means copying the entire data structure, you're passing by reference.

I guess what I'm trying to figure out is, what exactly occurs when you dereference a pointer? What does the compiler do? (My assumption was that it essentially it copied the value the pointer pointed too and passed that as an argument)
« Last Edit: July 09, 2012, 09:17:19 pm by GetOutOfBox »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: sf::Sprite/Texture(/Image) and pointers
« Reply #6 on: July 09, 2012, 09:29:31 pm »
Passing to/returning from functions and dereferencing are independent operations. Take a look at each one separately.

The dereferencing operator * transforms a pointer to an object into a reference to the object.
int var;
int* ptr = &var;
int& ref = *ptr; // same as: int& ref = var;

When function parameter and return types are neither pointers nor references, the object is passed/returned by value, i.e. a copy is performed. Here it doesn't matter whether the original is a reference or an object. This behavior is not different from a direct copy:
int var;
int& ref = var;
int copy = ref; // same as: int copy = var;

You can now combine both.
int var;
int* ptr = &var;
int copy = *var; // same as: int& ref = *var; int copy = ref;

It is easy to see that dereferencing doesn't include copy operations, otherwise you could neither dereference non-copyable objects, nor change the value of an object by dereferencing the pointer to it (as dereferencing would yield an independent copy, not a reference to the object itself).
« Last Edit: July 09, 2012, 09:36:42 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

GetOutOfBox

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: sf::Sprite/Texture(/Image) and pointers
« Reply #7 on: July 10, 2012, 05:40:34 pm »
Ah, I see! Alright thanks for all the help and patience guys, that's one of the reasons I switched to SFML, the great community :)