Sign in to follow this  
Waterlimon

Assigning A to B without B destroying all the allocations...

Recommended Posts

So i have the situation, where i have a class that contains some allocated data (in this case an opengl vertex buffer allocated on the GPU). I have a grid of these objects, and i want to move them all to a bigger grid.
This means doing something along the lines of
bigGrid[x]=smallGrid[x]
that is,
1.A=B
2.~B()
Which is a problem since i have set my vertex buffer deallocate itself upon destruction. How would you recommend me to overcome this problem? Should i use the newish move semantics here?

Thanks

Oh and the original grid is destroyed after copying all of them. So im basically just moving them. Edited by Waterlimon

Share this post


Link to post
Share on other sites
C++11 move assignment would work. Assuming your class implemented the move assignment operator you could invoke it with bigGrid[x] = std::move(smallGrid[x]); Another possibility is to go through and do bigGrid[x].swap(smallGrid[x]) if you implement an appropriate swap() function. How you would implement these would, of course, depend on what your class looks like.

Share this post


Link to post
Share on other sites

The problem is that this copying happens in a template class, so i cant really use a swap...

 

I assume move will work for any type i pass in properly, but will i need to implement the operators required for moving in only the vertex buffer or both the vertex buffer and the class containing it?

 

I read that in some situations on some compilers i would only need to implement it in the vertex buffer but that "some" also means im not going to do that. If this is true, it would be quite inconvenient and i might forget to implement the move for some class in a hierarchy of classes with a vertexbuffer somewhere, resulting in a bug :/

 

Reference counting might be something i can trust but i think that would require allocating the reference count variable which isnt nice.

Share this post


Link to post
Share on other sites

To use move semantics you need a move assignment operator on the class being moved, not the buffer.

 

You can also use a buffer of unique_ptr, but this will mean that the class is allocated seperately on the heap, instead of as a continious block in the buffer.

Share this post


Link to post
Share on other sites

You can also use a buffer of unique_ptr, but this will mean that the class is allocated seperately on the heap, instead of as a continious block in the buffer.

 

Just want to point out that, depending on what you're doing and what else is in your class, this could be perfectly fine. You'll still pay the indirection, but in terms of cache performance it might be better than if you were to have a buffer allocated as part of your class (it sounds like its heap allocated anyhow, but its not entirely clear without the source).

 

There are two downsides I can think of with this approach.

  1. The lesser issue: You can't share the data. If you needed to share it, then use shared_ptr -- you pay the cost of the reference count, but its per-shared-object, not per-sharing-object; that is, the cost is amortized across the classes sharing the object, rather than scaling up with them.
  2. The bigger issue: You essentially lose the ability to ever take any copy without destroying the original, including passing by value.

 

Enabling move semantics is also fine, this is exactly the situation it was intended for.

Edited by Ravyne

Share this post


Link to post
Share on other sites
How do you propose that you can take a copy of an object that contains a unique_ptr? You have to move (as in std::move) the unique_ptr's ownership to the copy, thus the unique_ptr in the original object no longer owns what it was pointing to, or even has its address.

The original object is not destructed, but it no longer holds that reference. Its incomplete and probably worthless.

[Edit] See my follow-up below. Edited by Ravyne

Share this post


Link to post
Share on other sites

I read your post to imply that you can't pass a copy of the contained object. But for the container, you can explicitly deep-copy it in a wrapper class (which you often want to have anyway). Also, you generally want to avoid coping big containers anyway.

Edited by King Mir

Share this post


Link to post
Share on other sites

To follow up, you can't just copy a unique_ptr because its it doesn't support copy-construction or copy-assign -- to move the contents of one unique_ptr into another, you explicitly release the source ptr and explicitly reset the destination ptr to the source. Because this is not provided for, your own objects that contain unique_ptr objects cannot be trivially copied either.

 

To clarify the point I was trying to get across, to make your own unique_ptr-containing objects copyable you have to implement your copy constructor and copy-assignment operator to explicitly exchange ownership of those unique_ptr resources. However, doing that hides the ownership semantics from client code in a non-obvious way. A preferable solution would be for your own objects to either expose an explicit release/reset interface (like unique_ptr) themselves. There might also be ways to implement the object which neatly side-steps the transfer of ownership (such as by adding a level of indirection, or some kind of "wrapper" as King Mir might be suggesting), but I honestly have a hard time thinking of any use-cases that wouldn't simply be better off using shared_ptr in the first place.

Share this post


Link to post
Share on other sites

Why would you want the container copying to exchange ownership? Similarly, using shared pointers doesn't make sense, because changes to the copy will affect the original. For a container, copying should generally deep-copy every element.
Copy on write semantics can also be useful, as an optimization. Or just don't allow copying.

 

It's true that the default copy operatations wouldn't work if your class holds unique pointers, but you can still write copy operations that do the right thing yourself. Alternatively, you could write your own smart pointer that has the right copy semantics, and an efficient move. I suspect in this case the way to go is to just modify the contained object to have move semantics.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this