Wrapping an opengl object into a c++ class with copying - c++

How is this usually done?
For example you might have a texture class. This would of course hold the GLuint id, and maybe other fields such as width and height. When the object needs to be copied for whatever reason, a user-defined copy constructor is needed.
Now, in the case of an opengl texture, it is possible to copy it to another texture object. But what about shader programs, or FBOs? These can't be copied so easily. How do people usually go about doing this? Should they be reference counted? Should copying be disabled on all objects? Should copying be disabled on all objects that can't be copied?
What is the best way to go about this? Thanks in advance for any answers.

For something like a texture there may actually be a point to copying it, but for a shader object much less so (in my experience). Even for objects where copying makes sense, you don't want to do it very often so you want to make it very explicit.
Either you use your wrapper class by-value (so it is something like a handle to your OpenGL entity) and it uses reference counting internally, or you consider your wrapper class instance to own the OpenGL entity and you use reference counting on your wrapper class itself (using std::shared_ptr for example).
In the latter case you could implement a copy-constructor only on those entities for which it makes sense. However, in order to avoid unintentional use I normally resort to a private constructor and a public static factory function on the entity that returns a new instance as a smart pointer, so it is not mistakenly used by-value. In that case it also makes more sense to have an explicit "Copy/Clone" member function (easier to use and it allows for polymorphism).
In the former case the copy-constructor only increments the reference count, so you will need to add some explicit member for copying where appropriate anyway.
I usually go with the latter option by the way... I'm used to passing resource-intensive objects around by smart pointers and I don't see much point in reimplementing their functionality in custom handles.

Related

C++ parametrized constructor

i was wondering if parametrized constructor should always have only parameters that actually initialize class' attributes. For example, in calling:
Texture background("C:\Documents\Images\background.png");
What if i don't need to store the file path?
An object constructor takes whatever parameters are necessary for returning a valid and functional object. You may allow constructors with extra parameters for syntax sugar, but at the very least, your object should be a valid one. In your case, I don't think a texture makes sense without a file used as texture, so I think removing that parameter is not recommended.
Keep in mind though that you should also aim for making your code easy to test. In that case, complex constructors can be a pain when you want to instantiate an object for testing specif methods. In the end, it is more of a decision process.
If you don't need to store the path, then don't pass it to the constructor! :)
Parametrized constructors are intended to ensure that all information is available when the object is instanciated. So pass only the information that is neccessary.
If you want to follow the RAII idiom, then pass all requered resource to the constructor and release the resources (if the object locks them, like a file or a port).
I don't think there's anything wrong with accepting a parameter which isn't directly stored in the class. Obviously if it doesn't affect the class at all, then that's just a waste of time, but you might accept something like a PRNG seed which you use to fill your class with randomised state, and have no reason to retain the seed beyond that point.
However, passing in a file path which you mean to access within the constructor is dangerous, as there could be any number of problems that come up during that process. You really don't want trouble like that in your constructor.
In avoiding potential failure cases in your constructor you end deferring things like file access until after construction. Consequently the constructor really doesn't need the information because it makes more sense to pass it to the method you use to access the file where you can handle errors more easily.

std::shared_ptr in a union

I'm implementing a "variant" class which must have the smallest possible memory footprint and store some objects with a shared pointer mechanism.
For this, I would like to make a union within the class of all variable types. This includes some shared_ptr's.
The operator= and copy constructors must change the data type of the variant, hence switching to another member in the union. Upon switching to a shared_ptr, this one should be reset to null without deleting/deowning the pointer. Is there a way to do this?
Of course, there would be other ways to implement this but they are generally more complex, less safe or more memory consuming in my case. Any suggestion welcome though.
Thanks!
Resetting to null isn't sufficient; the implementations of
std::shared_ptr I know also have a pointer to the reference
count, which must be deleted as well.
You need to keep track of what is currently in the union, and
use explicit calls to the destructor and placement new for
construction any time the type changes (and in the constructors
and the destructor).

When should you make a class uncopyable?

According to the Google style guidelines, "Few classes need to be copyable. Most should have neither a copy constructor nor an assignment operator."
They recommend you make a class uncopyable (that is, not giving it a copy constructor or assignment operator), and instead recommending passing by reference or pointer in most situations, or using clone() methods which cannot be invoked implicitly.
However, I've heard some arguments against this:
Accessing a reference is (usually) slower than accessing a value.
In some computations, I might want to leave the original object the way it is and just return the changed object.
I might want to store the value of a computation as a local object in a function and return it, which I couldn't do if I returned it by reference.
If a class is small enough, passing by reference is slower.
What are the positives/negatives of following this guideline? Is there any standard "rule of thumb" for making classes uncopyable? What should I consider when creating new classes?
I have two issues with their advice:
It doesn't apply to modern C++, ignoring move constructors/assignment operators, and so assumes that taking objects by value (which would have copied before) is often inefficient.
It doesn't trust the programmer to do the right thing and design their code appropriately. Instead it limits the programmer until they're forced to break the rule.
Whether your class should be copyable, moveable, both or neither should be a design decision based on the uses of the class itself. For example, a std::unique_ptr is a great example of a class that should only be moveable because copying it would invalidate its entire purpose. When you design a class, ask yourself if it makes sense to copy it. Most of the time the answer will be yes.
The advice seems to be based on the belief that programmers default to passing objects around by value which can be expensive when the objects are complex enough. This is just not true any more. You should default to passing objects around by value when you need a copy of the object, and there's no reason to be scared of this - in many cases, the move constructor will be used instead, which is almost always a constant time operation.
Again, the choice of how you should pass objects around is a design decision that should be influenced by a number of factors, such as:
Am I going to need a copy of this object?
Do I need to modify this object?
What is the lifetime of the object?
Is the object optional?
These questions should be asked with every type you write (parameter, return value, variable, whatever). You should find plenty of uses for passing objects by value that don't lead to poor performance due to copying.
If you follow good C++ programming practices, your copy constructors will be bug free, so that shouldn't be a concern. In fact, many classes can get away with just the defaulted copy/move constructors. If a class owns dynamically allocated resources and you use smart pointers appropriately, implementing the copy constructor is often as simple as copying the objects from the pointers - not much room for bugs.
Of course, this advice from Google is for people working on their code to ensure consistency throughout their codebase. That's fine. I don't recommend blindly adopting it in its entirety for a modern C++ project, however.

C++:using pointer to unordered_map or just defining it as a member variable from this type in a class?

I have a problem which I cannot understand:
Let's Say I have a class System with several member fields, and one of them is of type unordered_map, so when I declare the class in the header file, I write at the beginning of the header #include <unordered_map>.
Now, I have two ways of declaring this field:
1.std::unordered_map<std::string,int> umap;
2.std::unordered_map<std::string,int>* p_umap;
Now in the constructor of the class, if I choose the first option, there is no need to initialize that field in the initializer list since the constructor of class System will call the default constructor for the field umap as part of constructing an instance of type class System.
If I choose the second option, I should initialize the field p_umap in the constructor (in the initialize list) with the operator new and in the destructor, to delete this dynamic allocation.
What is the difference between these two options? If you have a class that one of it's fields is of type unordered_map, how do you declare this field? As a pointer or as a variable of type unordered_map?
In a situation like the one you are describing, it seems like the first option is preferable. Most likely, in fact, the unordered map is intended to be owned by the class it is a data member of. In other words, its lifetime should not be extended beyond the lifetime of the encapsulating class, and the encapsulating class has the responsibility of creating and destroying the unordered map.
While with option 1 all this work is done automatically, with option 2 you would have to take care of it manually (and take care of correct copy-construction, copy-assignment, exception-safety, lack of memory leaks, and so on). Surely you could use smart pointers (e.g. std::unique_ptr<>) to encapsulate this responsibility into a wrapper that would take care of deleting the wrapped object when the smart pointer itself goes out of scope (this idiom is called RAII, which is an acronym for Resource Acquisition Is Initialization).
However, it seems to me like you do not really need a pointer at all here. You have an object whose lifetime is completely bounded by the lifetime of the class that contains it. In these situations, you should just not use pointers and prefer declaring the variable as:
std::unordered_map<std::string, int> umap;
Make it not a pointer until you need to make it a pointer.
Pointers are rife with user error.
For example, you forgot to mention that your class System would also need to implement
System( const Sysytem& )
and
System& operator= ( const System& )
or Bad Behavior will arise when you try to copy your object.
The difference is in how you want to be able to access umap. Pointers can allow for a bit more flexibility, but they obviously add complexity in terms of allocation (stack vs heap, destructors and such). If you use a pointer to umap, you can do some pretty convoluted stuff such as making two System's with the same umap. In the end though, go with KISS unless there's a compelling reason not to.
There is no need to define it as pointer. If you do it, you must also make sure to implement copy constructor and assignment operator, or disable them completely.
If there is no specific reason to make it a pointer (and you don't show any) just make it a normal member variable.

C++:member reference or pointer?

I have a collection (currently boost::ptr_vector) of objects (lets call this vec) that needs to be passed to a few functors. I want all of the functors to have a reference/pointer to the same vec which is essentially a cache so that each functor has the same data cache. There are three ways that I can think of doing this:
Passing a boost::ptr_vector<object>& to the constructor of Functor and having a boost::ptr_vector<object>& member in the Functor class
Passing a boost::ptr_vector<object>* to the constructor of Functor and having a boost::ptr_vector<object>* member in the Functor class
avoid the use of boost::ptr_vector and directly pass an array (object*) to the constructor
I have tried to use method 3, but have been told constantly that I should use a vector instead of a raw pointer. So, I tried method 2 but this added latency to my program due to the extra level of indirection added by the pointer. I am using method 1 at the moment, however I may need to reassign the cache during the lifetime of the functor (as the data cache may change) so this may not be an appropriate alternative.
Which I don't fully understand. I assume somewhere along the way the functor is being copied (although these are all stored in a ptr_vector themselves).
Is method 3 the best for my case? method 2, is too slow (latency is very crucial), and as for method 1, I have been advised time and again to use vectors instead.
Any advice is much appreciated
A reference in C++ can only be initialized ('bound') to a variable.
After that point, a reference can not be "reseated" (made to refer to a different variable) during it's lifetime.
This is why a default copy constructor could conceivably be generated, but never the assignment operator, since that would require the reference to be 'changed'.
My recommended approach here is to use a smart pointer instead of a reference.
std::unique_ptr (simplest, takes care of allocation/deallocation)
std::shared_ptr (more involved, allows sharing of the ownership)
In this case:
std::shared_ptr<boost::ptr_vector<object> > m_coll;
would seem to be a good fit