Will a non-default copy constructor slow my program down? - c++

I have a class named Texture that has a pointer to a SDL_Surface. When I want to add it to a vector I need to have a non-default copy constructor to prevent problems when the original goes out of scope. I know that the copy constructor is called whenever the object is passed by value to a function. Will passing many Texture objects by value to my render function every frame cause my program to slow down? I know I can pass by reference to avoid this problem but I would like to keep my existing code as is if possible.

First of all, if you are really concerned about performance, then you should be passing references around, passing by value could get very expensive, no matter if you use the default or a custom copy constructor.
Now, if you are completely set on passing stuff by value and using copy constructors, I think the default copy constructor is nice, because it takes care of everything for you. You should try to adapt your class so that you can continue using it, if possible.
If your class has pointers, then one approach is to wrap them inside some kind of smart pointer. For example, if instead of SDL_Surface* you use std::shared_ptr<SDL_Surface> (or boost::shared_ptr<SDL_Surface> which is the same) then you enable that pointer to be copied. The shared_ptr class will keep a reference count on it and only delete the surface when all the references are gone. Note that if you do this approach you need to use a custom delete function for SDL_Surface, as shown in this question.

Related

destruct and construct a class in order to clean its members

I have noticed that, in our codebase, there are some classes that are only used to hold data in their members. In order to clean the members, we call each class' clear() command. However, I've also noticed that, clean methods call other cleans and, which in cascade, results in calling clear() of std data types like string and vectors. Therefore, there seems to be a huge amount of redundant code written.
To minimize the amount of work in the reduction process I am planning to turn each clear method to the following. What are other details I may be missing and your suggestions?
void aClass::clear() {
this->~aClass();
*this = aClass();
}
Thank you
You are missing that your call to the destructor is wrong here. You could simply assign:
*this = aClass();
However, then
This is not what a clear method is supposed to do. You are creating a new object not clearing it. If you clear a string then no reallocations need to happen. Deleting a string and creating a new one is really more work, not less.
As a corrollary to the first point, clear does not take parameters, while your constructor probably does. Again, default constructing a new instance is not what is expected from clear and sometimes it isn't even possible (when there is no default constructor).
Moreover, lets say you do implement clear like this. Then the method adds nothing that the user of the class could not do with a call to a constructor. Instead x.clear(); they could write x = aClass();.
Summary: If you have lots of code to clear objects in your code base, then this is very likely for a reason. Clearing an instance can usually be done with much less computational effort than creating a new instance. On the other hand if this is not the case, then there is no point in implementing a clear method (provided that there is an accessible constructor to create a new instance).
What are other details I may be missing
The destructor still clears the standard containers that are destroyed. Not only that, but it also re-creates them at a cost.
References to the cleared object will become invalid. This can easily lead to undefined behaviour unless you are careful.
and your suggestions?
Write a normal function that doesn't involve the destruction of the object.
Nooooooooooooooooooooo.
Don't do that.
The destructor isn't just a function that calls some operations on your members.
It ends the lifetime of your object.
Period. Full stop.
You cannot call the destructor then keep using the object. Invoking its assignment operator with a temporary doesn't bring it back to life, either; that just, well, invokes the assignment operator to change some values. Values that no longer exist.
There are a few cases where invoking the destructor is reasonable, but they all involve "very manual memory management" using placement new. There are basically no other acceptable times to do it.
Review the notion of object lifetime in C++.
If your copy assignment operator is correctly written, then just *this = aClass(); is already fine for resetting your objects. You might also consider aClass().swap(*this), with the appropriate move-capable swap being added to your class.
These are not "redundant" operations.

C++ global object losing values

I have a class called Player_Sprite. I have declared an instance of it globally like this:
Header:
shared_ptr <Player_Sprite> MainPlayer;
CPP:
shared_ptr <Player_Sprite> MainPlayer = make_shared<Player_Sprite>();
I've tried:
Player_Sprite player = (*MainPlayer);
//Do more here
I've noticed I will lose values previously set with player.
Player.SetState(Moving); //Example
Player will lose his state however and still be at Stopped.
However do I refer to this instance of Player_Sprite without using -> that won't just copy it and leave me wondering where my values went?
Just use the shared_ptr as if it was a normal pointer:
MainPlayer->SetState(Moving);
That’s how it’s intended to be used.
Player_Sprite player = (*MainPlayer);
would just dereference the player and make a copy of it. If you change the copy, the original, of course, won’t change.
Player_Sprite player = (*MainPlayer); will take a value copy of *MainPlayer. This accounts for your "losing values".
Use Player->SetState(Moving); instead. std::shared_ptr has a clever overload for the pointer to member operator -> which means you can use it as you would for a bare pointer.
It would be even better if you could change your case conventions to something more standard, so you could write the considerably more readable
player->setState(Moving);

How would a QList containing pointers behave when passed by value

Suppose you have QList containing pointers QList<SomeThingCool*> and you pass it to a method with a signature void doCoolStuff(QList<SomeThingCool*> list) what would the space and time implications be of such a call?
My guess is that there will be some overhead because a copy will be created of the QList object, we however do not need to do a deep copy since we are dealing with pointers.
One difference in behaviour would be that if doCoolStuff makes modifications to the list, the original list will remain untouched.
What you are writing is correct for generic C++, however QList, among some other Qt classes, is a bit special when it comes to this. It is implicitly shared a class, aka. copy-on-write (COW). What does that mean, yeah?
The only addition to your explanation is that if you do not intend to modify the list inside the body of the method or function, your list be implicit shared, which means a shared data pointer will be only the extra space constraint.
If you intend to modify the list inside the function or method body, then there will be a deep copy made for the list. Naturally, your pointers will still remain shallowly copied because they are pointers.
As for the time dimension, by implicitly using this technique for this class, you spare the time spent on copying the list if you do not do any modification.

Move semantics, standard collections, and construction time address

Of course I would like to know some magic fix to this but I am open to restructuring.
So I have a class DeviceDependent, with the following constructor
DeviceDependent(Device& device);
which stores a reference to the device. The device can change state, which will necessitate a change in all DeviceDependent instances dependent on that device. (You guessed it this is my paltry attempt to ride the directX beast)
To handle this I have the functions DeviceDependent::createDeviceResources(), DeviceDependent::onDeviceLost().
I planned to register each DeviceDependentinstance to the device specified in the DeviceDependent constructor. The Device would keep a std::vector<DeviceDependent*> of all DeviceDependent instances so registered. It would then iterate through that vector and called the above functions when appropriate.
This seemed simple enough, but what I especially liked about it was that I could have a std::vector<DeviceDependent (or child)> somewhere else in the code and iterate over them quickly. For instance I have a class Renderable which as the name suggest represents a renderable object, I need to iterate over this once a frame at least and because of this I did not want the objects to be scattered throughout memory.
Down to business, here is the problem:
When I create the solid objects I relied on move semantics. This was purely by instinct I did not consider copying large objects like these to add them to the std::vector<DeviceDependent (or child)> collection. (and still abhor the idea)
However, with move semantics (and I have tested this for those who don't believe it) the address of the object changes. What's more it changes after the default constructor is called. That means my code inside the constructor of DeviceDependant calling device.registerDeviceDependent(this) compiles and runs fine, but the device accumulates a list of pointers which are invalidated as soon as the object is moved into the vector.
I want to know if there is someway I can stick to this plan and make it work.
Things I thought of:
Making the 'real' vector a collection of shared pointers, no issue copying. The object presumably will not change address. I don't like this plan because I am afraid that leaving things out on the heap will harm iteration performance.
Calling register after the object has been moved, it's what I'm doing provisionally but I don't like it because I feel the constructor is the proper place to do this. There
should not exist an instance of DeviceDependent that is not on some device's manifest.
Writing my own move constructor or move assignment functions. This way I could remove the old address from the device and change it to the new one. I don't want to do this because I don't want to keep updating it as the class evolves.
This has nothing to do with move constructors. The issue is std::vector. When you add a new item to that vector, it may reallocate its memory, and that will cause all the DeviceDependant objects to be transferred to a new memory block internal to the vector. Then new versions of each item will be constructed, and the old ones deleted. Whether the construction is copy-construction or move-construction is irrelevant; the objects effectively change their address either way.
To make your code correct, DeviceDependant objects need to unregister themselves in their destructor, and register themselves in both copy- and move-constructors. You should do this regardless of what else you decide about storage, if you have not deleted those constructors. Otherwise those constructors, if called, will do the wrong thing.
One approach not on your list would be to prevent the vector reallocating by calling reserve() with the maximum number of items you will store. This is only practical if you know a reasonable upper-bound to the number of DeviceDependant objects. However, you may find that reserving an estimate, while not eliminating the vector reallocations entirely, makes it rare enough that the cost of un-registering and re-registering becomes insignificant.
It sounds like your goal is getting cache-coherency for the DeviceDependants. You might find that using a std::deque as main storage avoids the re-allocations while still giving enough cache-coherency. Or you could gain cache-coherency by writing a custom allocator or operator new().
As an aside, it sounds like your design is being driven by performance costs that you are only guessing at. If you actually measure it, you might find that using std::vector> is fine, and doesn't significantly the time it takes to iterate over them. (Note you don't need shared pointers here, since the vector is the only owner, so you can avoid the overheads of reference-counting.)

Can I make a bitwise copy of a C++ object?

Can C++ objects be copied using bitwise copy? I mean using memcopy_s? Is there a scenario in which that can go wrong?
If they're Plain Old Data (POD) types, then this should work. Any class that has instances of other classes inside it will potentially fail, since you're copying them without invoking their copy constructors. The most likely way it will fail is one of their destructors will free some memory, but you've duplicated pointers that point to it, so you then try to use it from one of your copied objects and get a segfault. In short, don't do it unless it's a POD and you're sure it will always be a POD.
No, doing so can cause a lot of problems. You should always copy C++ types by using the assignment operator or copy constructor.
Using a bitwise copy breaks any kind of resource management because at the end of the day you are left with 2 objects for which 1 constructor has run and 2 destructors will run.
Consider as an example a ref counted pointer.
void foo() {
RefPointer<int> p1(new int());
RefPointer<int> p2;
memcpy(&p2,p1,sizeof(RefPointer<int>));
}
Now both p1 and p2 are holding onto the same data yet the internal ref counting mechanism has not been notified. Both destructors will run thinking they are the sole owner of the data potentially causing the value to be destructed twice.
It depends on the implementation of the C++ object you are trying to copy. In general the owner of the C++ object's memory is the object itself, so trying to "move" or "copy" it with something like memcopy_s is going behind its back which is going to get you in trouble more often than not.
Usually if a C++ object is intended to be copied or moved, there are APIs within the class itself that facilitate this.
If it is a single object, why not use assignment operator (I suppose the compiler-generated assignment operator could be implemented in terms of memcpy if that is so advantageous, and the compiler knows better whether your class is a POD.)
If you want to copy an array of objects, you can use std::copy. Depending on the implementation, this may end up using memmove (one more thing that you can mess up - the buffers may overlap; I don't know whether the nonstandard memcpy_s somehow checks for that) if the involved types allow that. Again, the decision is done by the compiler, which will get it right even if the types are modified.
In general if your structure contains pointers, you can't memcpy it because the structure would most likely allocate new memory spaces and point to those. A memcpy can't handle that.
If however your class only has primitive, non-pointer types, you should be able to.
In addition to the problem of unbalanced resource management calls in the two instance you end up with after a memcopy (as #JaredPar and #rmeador pointed), if the object supports a notion of an instance ID doing a memcopy will leave you with two instances with the same ID. This can lead to all sorts of "interesting" problems to hunt later on, especially if your objects are mapped to a database.