Jump to content
  • Advertisement
Sign in to follow this  
MatthewDiaz

Pointers going bad in vector of a class

This topic is 2298 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 am coding with MSVC++ and Directx11. I am using [font=Consolas][font=Consolas]D3DX11CreateShaderResourceViewFromFile and [font=Consolas][font=Consolas]D3DX11CompileFromFile which both require a LPCSTR and char* member respectively. [font=Consolas]My GameSprite class holds these two members. Now my game editor saves important info from my GameSprite class. Now when I save one single class I Load it just fine which I do manually. I use my own code for saving and loading. Now when I load a vector of GameSprites, whenever I push_back to load a new one the pointer information for those two members are no longer valid in previous elements. However, I got it working by making a function which reset all that information after the vector was full and loaded. I am able to do it because I save and load std::string and just convert them to and from char* and LPCSTR. My question is do I have to do this? Why don't the pointers stay valid when I push on the vector? Oh and I use ifstream and ofstream to do the saving/loading.[/font][/font][/font][/font][/font]

Share this post


Link to post
Share on other sites
Advertisement
Changes to containers can affect their address, which invalidates pointers.


Adding or inserting to a vector is one of those changes. If it needs to grow the vector it can cause all the addresses to become invalid. If you need to remove an element it invalidates everything after that element. Other operations can similarly invalidate existing pointers.

Compare that to a std::list, where adding and removing elements does not invalidate existing items.

Share this post


Link to post
Share on other sites

[font=Consolas][font=Consolas][font=Consolas][font=Consolas][font=Consolas]Why don't the pointers stay valid when I push on the vector?[/font][/font][/font][/font][/font]



When you push_back your first element, the vector might over-allocate in anticipation of you adding additional elements soon. Let's say it's initial buffer is large enough to store 8 elements. But as soon as you push_back your 9th element, a new, larger buffer has to be reallocated and the existing elements are copied in to there. Therefore, any pointers you had that referred to elements in the first buffer now point to reclaimed memory with arbitrary content. The new buffer is typically something like twice as big as the previous buffer size, but it is exhaustible in just the same way, and reallocation will occur again (and again...) if you keep appending elements.

Using a different container might solve the problem e.g. std::list as frob suggests. If random access is important to you and you're not inserting or erasing elements in the middle, std::deque might be a better choice.

Microsoft's concurrent_vector also maintains stable element locations (though be careful as the storage is only piecewise-contiguous), though there's little reason to choose it over std::deque unless you're appending from multiple threads at a time.

An easier solution might simply to be to store indices, rather than pointers.

Or, if you know that you'll never need to store more than N elements in the vector, use the reserve() method to ensure a buffer of sufficient size is allocated upfront.

Share this post


Link to post
Share on other sites

[quote name='ILoveJesus' timestamp='1331244412' post='4920521']

[font=Consolas][font=Consolas][font=Consolas][font=Consolas][font=Consolas]Why don't the pointers stay valid when I push on the vector?[/font][/font][/font][/font][/font]



Or, if you know that you'll never need to store more than N elements in the vector, use the reserve() method to ensure a buffer of sufficient size is allocated upfront.
[/quote]


Thank you that seems to be the best option if I want to continue using a vector here. Less code and there is no need for a function that resets those pointers. By the way what is the difference between resize and reserve? I had problems with resize in the past. For one large vector of a class it would put more elements in the vector than i told it to. I never could figure out why.

Share this post


Link to post
Share on other sites

By the way what is the difference between resize and reserve?


std::vector<T>::resize(n) allocates buffer of sufficient capacity to store n objects and also initialize any elements needed via calls to T's copy constructor. There's a second argument to resize that accepts a T object to be copied in to newly created elements, but by default it's a default-initialized T object. After a call to resize(n), the size() method will return n.

std::vector<T>::reserve(n) on the other hand, will ensure that there's sufficient space in the buffer to hold n T objects, but it will not initialize those elements. This means the size() will not change after a call to reserve(). Calls to e.g. push_back() will copy elements in to that reserved space until it is full, when reallocation will occur as previously described.

So:


std::vector<std::string> vs1;
vs1.resize(10, "hello");

assert(vs1.size() == 10);
assert(vs1[7] == "hello");


std::vector<std::string> vs2;
vs2.reserve(10);

assert(vs2.size() == 0);
assert(vs2.capacity() >= 10); // capacity will tell you the total number of elements that can exist in the vector before reallocation is required.
// vs2[7] = "NO"; // DON'T DO THIS!! string objects have not been initialized in that memory yet.

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!