Instantiate an object in method vs. make a class member - c++

What are some reasons to instantiate an object needed in a method, vs. making the object a class member?
For example, in the example code below, I have a class ClassA that I want to use from another class, like USer1, which has pointer to object of classA as member variable and instantiates in its constructor, and on the other hand User2, which instantiates object of classA in a method just before using it. What are some reasons to do it one way vs the other?
class ClassA
{
public:
void doStuff(void){ }
};
//
// this class has ClassA as a member
//
class User1
{
public:
User1()
{
classA = new ClassA();
}
~User1()
{
delete classA;
}
void use(void)
{
classA->doStuff();
}
private:
ClassA *classA;
};
//
// this class uses ClassA only in a method
//
class User2
{
public:
void use(void)
{
ClassA *classA = new ClassA();
classA->doStuff();
delete classA;
}
};
int main(void)
{
User1 user1;
user1.use();
User2 user2;
user2.use();
return 0;
}

The advantages of making it a class member are:
You don't have to allocate the instance every time, which depending on the class could be very slow.
The member can store state (though some people would say that this is a bad idea)
less code
As a side note, if you are just instantiating and deleting with new and delete in the constructor and destructor, it should really not be a pointer, just a member instance and then get rid of the new and delete.
IE
class User1
{
public:
void use(void)
{
classA.doStuff();
}
private:
ClassA classA;
};
There are times that this isn't the case, for instance when the class being allocated on the stack is large, or you want the footprint of the holding class to be as small as possible. But these are the exception rather than the rule.
There are other thing to consider like memory fragmentation, the advantages of accessing contiguous memory blocks, and how memory is allocated on the target system. There are no silver bullets, only general advice, and for any particular program you need to measure and adjust to get the best performance or overcome the limitations of the particular program.
Memory fragmentation is when even though you have a lot of memory free, the size of the individual block is quite small and you will get memory errors when you try to allocate a large amount of memory. This is usually caused by creating and destroying a lot of different objects of various sizes, with some of them staying alive. If you have a system that suffers from memory fragmentation I would suggest a thorough analysis of how objects are created rather than worry about how having a member or not will affect the system. However, here is a breakdown of how the four different scenarios play out when you are suffering from memory fragmentation:
Instantiating the class on the stack is very helpful as it won't contribute to overall memory fragmentation.
Creating it as a value member might cause problems as it might increase the overall size of the object, so when you get to the fragmentation scenario, the object may be too large to be created.
Creating the object and storing a pointer to it may increase memory fragmentation
Allocating on the heap and deleting at the end of use may increase memory fragmentation if something else is allocated after it was.
The advantages of accessing contiguous memory is that cache misses are minimised, so my feeling is that having the object as a value member would be faster, but as with so many things depending lots of other variables this could be completely wrong. As always when it comes to performance, measure.
Memory is often aligned to a particular boundary, for instance 4 byte alignment, or power of 2 blocks. So depending on the size of your object when you allocate one of them it might take up more memory than you expect, if your allocated object contains any members it might significant change the memory footprint of the class if it is a value member, or if it doesn't it probably won't increase it at all, while having a pointer to it will definitely increase the footprint by the size of a pointer, and that may result in a significant increase. Either creating the class on the heap or the stack will not affect the size of the using class. As always if it is going to affect your program you need to measure on the target system to see what the effects are going to be.
If the constructor/destructor does something (for instance a file handle, opening the file, and closing the file) then you might want to only use it in the function. But yet again, the pointer isn't usually necessary.
void use(void)
{
ClassA classA;
classA.doStuff();
} //classA will be destructed at end of scope

First off there is no reason to have a pointer in either class. If we use value semantics in User1 then there is no need to have a constructor or destructor as the compiler generated ones will be sufficient. That changes User1 to:
class User1
{
public:
void use(void)
{
classA.doStuff();
}
private:
ClassA classA;
};
Likewise if we use value semantics in User2 then it would become:
class User2
{
public:
void use(void)
{
ClassA classA;
classA.doStuff();
}
};
Now as to whether you want to have ClassA as a member or if you should just use it in the function is a matter of design. If the class is going to be using and updating the ClassA then it should be a member. If you just need to to do something in a function the the second approach is okay.
If you are going to be calling the function that creates a ClassA a lot it might be beneficial to have it be a member as you only need to construct it once and you get to use it in the function. Conversely If you are going to have a lot objects but you hardly ever call that function it might be better to create the ClassA when you need it as you will save space.
Really though this is something that you would have to profile to determine which way would be better. We programmers are bad judges of what is faster and should let the profiler tell us if we need to change something. Some things like using value semantics over a pointer with heap allocation is generally faster. One example where we get this wrong is sorting. If N is small then using a bubble sort which is O(n^2) is faster than a quicksort which is O(n log n). Another example of this si presented in this Hurb Sutter talk starting at 46:00. He shows that using a std::vector is faster than a std::list at inserting and removing from the middle because a std::vector is very cache friendly where a std::list is not.

Related

Statically allocating array of inherited objects

The title of this question is pretty convoluted, so I'll try to frame it with an example. Let's say that I have an abstract base class, with a number of classes which inherit from it. In the example below I've only shown two inherited classes, but in reality there could be more.
class Base {
public:
Base();
virtual ~Base() = 0;
/// Other methods/members
};
class SmallChild: public Base {
public:
SmallChild();
~SmallChild();
/// Other methods/members such that sizeof(SmallChild) < sizeof(LargeChild)
};
class LargeChild : public Base {
public:
LargeChild();
~LargeChild();
/// Other methods/members such that sizeof(LargeChild) > sizeof(SmallChild)
};
I need to implement a container which stores up to N inherited objects. These objects need to be created/destroyed at runtime and placed in the container, but due to constraints in the project (specifically that it's on embedded hardware), dynamic memory allocation isn't an option. The container needs to have all of its space statically allocated. Also, C++11 is not supported by the compiler.
There was only one way I could think to implement this. To reference the N objects, I'd first need to create an array of pointers to the base class, and then to actually store the objects, I'd need to create a buffer large enough to store N copies of the largest inherited object, which in this case is LargeChild
Base * children[N];
uint8_t childBuffer[N * sizeof(LargeChild)];
I could then distribute the pointers in children across childBuffer, each separated by sizeof(LargeChild). As objects need to be created, C++'s "placement new" could be used to place them at the specified locations in the array. I'd need to keep track of the type of each object in childBuffer in order to dereference the pointers in children, but this shouldn't be too bad.
I have a few questions regarding this entire setup/implementation:
Is this a good approach to solving the problem as I've described it? I've never implemented ANYTHING like this before, so I have no idea if I'm way out to lunch here and there's a much easier way to accomplish this.
How much of this can be done at compile-time? If I have M types of inherited classes (SmallChild, LargeChild, etc.) but I don't know their size in relation to each other, how can I determine the size of childBuffer? This size depends on the size of the largest class, but is there a way to determine this size at compile-time? I can imagine some preprocessor macros iterating through the classes, evaluating sizeof and finding the maximum, but I have very little experience with this level of preprocessor work and have no idea what this would look like. I can also imagine this being possible using templates, but again, I don't have any experience with compile-time template sorcery so I'm only basing this on my intuition. Any direction on how to implement this would be appreciated.
Do you need to be able to dealocate the objects? If not, it may be easier to override operator new. I refer to this:
void* operator new (std::size_t size) throw (std::bad_alloc);
All your overrides would allocate memory from a sinle large buffer. How much memory to allocate is specified by the size parammeter.
This way you should be able to just say
children[i] = new SmallChild();
Edit: if you do need to deallocate, you need more complex data structures. You may end up re-implementing the heap anyway.
If the set of objects is fully static (set at build time and doesn't change at runtime), the usual approach is to use a set of arrays of each derived class and build up the 'global' array with pointers into the other arrays:
static SmallChild small_children[] = {
{ ...initializer for first small child... },
{ ...initializer for second small child... },
...
};
static LargeChild large_children[] = {
{ ...initializer for first large child... },
...
};
Base *children[N] = { &small_children[0], &small_children[1], &large_children[0], ....
This can be tricky to maintain if there are children being added/removed from the build frequently, or if the order in the children array is important. It may be desirable to generate the above source file with a script or build program that reads a description of the children needed.
Your approach is interesting, given your constraints (i.e. no use of dynamic allocation).
In fact you are managing on your own way a kind of array of union anyChild { smallChild o1; largeChild o2; ... }; The sizeof(anyChild) would give you the largest block size you are looking for.
By the way, there could be a risk of dangling pointers in you approach, as long as all objects have not been created with the the placement new, or if some of them are deleted through explicit call of their destructor.
if you put your derived types into a union:
union Child{
SmallChild asSmallChild;
LargeChild asLargeChild;
}
Then the union will automatically be of the sizeof the largest type. Of course, now you have a new problem. What type is represented in the union? You could give yourself a hint in the base Class, or you could instead make Child a struct which contains a hint and then the union inlined within. For examples look at components made by Espressif for ESP32 on the githubs, lots of good union uses there.
Anyways, when you go to allocate, if you allocate an array of the union'ed type it will make an array of largest children... because that's what unions do.

Alternatives for polymorphic data storage

I'm storing a large amount of computed data and I'm currently using a polymorphic type to reduce the amount of storage required. Everything is extremely fast except for deleting the objects when I'm finished and I think there must be a better alternative. The code computes the state at each step and depending on the conditions present it needs to store certain values. The worst case is storing the full object state and the best state is storing almost nothing. The (very simplified) setup is as follows:
class BaseClass
{
public:
virtual ~BaseClass() { }
double time;
unsigned int section;
};
class VirtualSmall : public BaseClass
{
public:
double values[2];
int othervalue;
};
class VirtualBig : public BaseClass
{
public:
double values[16];
int othervalues[5];
};
...
std::vector<BaseClass*> results(10000);
The appropriate object type is generated during computation and a pointer to it is stored in the vector. The overhead from vtable+pointer is overall much smaller than than the size difference between the largest and smallest object (which is least 200 bytes according to sizeof). Since often the smallest object can be used instead of the largest and there are potentially many tens of millions of them stored it can save a few gigabytes of memory usage. The results can then be searched extremely fast as the base class contains the information necessary to find the correct item which can then be dynamic_cast back to it's real type. It works very well for the most part.
The only issue is with delete. It takes a few seconds to free all of the memory when there is many tens of millions of objects. The delete code iterates through each object and delete results[i] which calls the virtual destructor. While it's not impossible to work around I think there must be a more elegant solution.
It could definitely be done by allocating largish contiguous blocks of memory (with malloc or similar), which are kept track of and then something generates a correct pointers to the next batch of free memory inside of the block. That pointer is then stored in the vector. To free the memory the smaller number of large blocks need to have free() called on them. There is no more vtable (and it can be replaced by a smaller type field to ensure the correct cast) which saves space as well. It is very much a C style solution though and not particularly pretty.
Is there a C++ style solution to this type of problem I'm overlooking?
You can overload the "new" operator (i.e. void* VirtualSmall::operator new(size_t) ) for you classes, and implement them to obtain memory from custom allocators. I would use one block allocator for each derived class, so that each block size is a multiple of the class' it's supposed to store.
When it's time to cleanup, tell each allocators to release all blocks. No destructors will be called, so make sure you don't need them.

member functions to free member variable memory

Recently I have noticed some of my objects become quite large and after a while I might not need them any longer. I could wait until the end of the local scope for the destructor to release the memory or use custom scopes using code blocks.
However, I had this idea to implement, for each object, a void MyObject::clear() method that clears the memory:
class MyObject{
bool is_cleared;
// Other stuff
public:
MyObject();
~MyObject();
void clear();
// Other stuff
};
MyObject::MyObject()
: is_cleared(false)
{
// construct the class
}
void MyObject::clear(){
if (!is_cleared){
// clear memory
is_cleared = true;
}
}
MyObject::~MyObject(){
this->clear();
}
This way I can either let the destructor clear the memory or do it myself. Is this considered a good or bad practice? How can I improve it?
There is nothing particularly bad with this technique (it is used by STL containers, for example). But you will also need to implement a copy constructor and an assignment operator (or make your object not copy-able and not assign-able). This is because you have implemented a destructor, so you will have to follow the rule of three.
It's bad practice. You should design ownership of objects in such a way that they are destructed when you "[don't] need them any longer".
This can be as simple as allocating the object on the heap and deleting it when you're done with it. It will then clean up any dynamic memory it allocated.
I would flag this as a bad practice.
First, you should free stuff you don't need as soon as possible if is it of significant size. You should not use members to store large data in an object if that data should not survive till the object dies. There should be few exceptions to this rule. If many of your objects require it, you are designing objets with too many responsibilities.
Then, did you measure that you need to clean the memory before ? If not this is likely to be an unecessary optimization. Just wait till they go out of scope, why bother ?

Limit the number of instances with the new keyword

I've been reading a lot of debates about whether the Singleton pattern is good/bad/ugly, and what should be used instead of it.
The common implementation requires an Instance() method that invokes a private constructor if the object has not yet been created.
My question doesn't really fit the Singleton pattern, but would it be possible to limit the number of instances of a class by overriding new? And if say we only want one instance, return the already created instance?
If this is possible is it even a good idea?
The aim would be that in any class needing access to a class, one would simply declare a private member, which would be initialized the first time, and then referenced for the rest.
ClassA {
MyClass classRef;
}
ClassB {
MyClass classRef;
}
So if MyClassis limited to one instance, depending on the order of instancing, one of these objects will actually create a new MyClass, and the other will just obtain it's reference.
Objects can be allocated statically, on the stack, and within other objects. If you want just one instance, you need to disallow all of these somehow. Overloading operator new won't help you with this. Making the constructors private or protected will, but this will disable operator new for the users of the class as well.
Moreover, what operator new returns is not an object, but a block memory in which the object will be created. If you return an already allocated block, a constructor will be run over it each time operator new is called.
This sounds like a non-concurrent worker pool of some sort.
This can be a good idea when a large number of jobs are going to be executed by more than one service/driver and you want to implement throttling, or perhaps queue jobs to prevent swap file thrashing, or some other resource constraint.
Overriding new is probably not the right way to do it. Have the task farm be an object itself, and "allocate" tasks from there. The raw allocation of the task handle wrapper object should be free from such considerations.
And yes, singletons are ugly (or at least an ugly implementation of a good idea).
Overriding new won't work. First, it won't prevent additional
instances on the stack or as static variables. Second, the operator
new that you define only allocates memory; the constructor will still
be called (with possibly disasterous effects if the singleton has
mutable state).
You can limit the number of instantiations much more straightforwardly by keeping a counter as a static member variable:
template<unsigned int N>
class N_gleton {
private:
static int number_of_instances_;
public:
enum { MAX_NUMBER_OF_INSTANCES = N };
N_gleton() {
assert(number_of_instances_ < MAX_NUMBER_OF_INSTANCES);
++number_of_instances_;
}
};
template<unsigned int N>
int N_gleton<N>::number_of_instances_ = 0; // initial value

What is the preferred way of allocating C++ class member data?

Let's say I have a class that allocates some arbitrary member data. There are two common ways that I have seen used (I know that there are others):
class A
{
public:
A();
~A();
//Accessors...
private:
B *mB;
}
A::A()
{
mB = new B();
}
A::~A()
{
delete B;
}
Versus...
class A
{
public:
//Accessors...
private:
B mB;
}
Assume that A itself will be allocated on the heap by consumer code.
In the general case, which method is preferred? I realize that specific situations really encourage one way or the other, but in absence of those demands, is one way preferred? What are the tradeoffs?
The second is the preferred route. Do not use new / delete unless you specifically need a variable to be on the heap or have a lifetime longer than it's container. C++ value types are easier to manage and have less error cases to worry about IMHO
It depends.
In general, If a B is large and unwieldy then it's easier to pass around a pointer to the B than the B itself. So if the B will often be disassociated from the A (f'rinstance if your A's swap B's) then the first way is better.
Using a pointer can also reduce dependencies. If you do it right, A.hh can get by without specifiying what a B is or does (i.e. A.h need not #include "B.hh") so that things that depend on A.hh won't necessarily depend on B.hh.
The price of using pointers is an extra layer of machinery and the dangers of things like lost objects, double-deletion and the dereferencing of uninitialized pointers, so it shouldn't be used unless it actually gives a benefit in your situation. Some people fall in love with pointer techniques and use them everywhere; if they want to improve as programmers they have to grow out of it.
In general, prefer direct composition (the second choice). In that case there is no chance of leaking memory and the object is fully located in a contiguous memory block, allowing better cache locality.
You might use the first option if you're implementing a PIMPL, or you have a need to use one of several possible class types (via inheritance). In that case definitely use a smart pointer (boost::shared_ptr for example) to manage the memory for you.
It depends, mainly, on what you are looking for.
For simplicity's sake: don't use a pointer. Therefore the second choice.
It's easier to manage (no need to worry about memory management, deep copying, deep constness, etc...).
However you might need dynamically allocated attributes sometimes:
if you need polymorphism (otherwise you have a truncation)
if you want to cut down your dependencies (in the header file) --> see PIMPL here
Even in this case though, hand over the responsibility to a smart manager (smart pointer, dedicated pimpl class, etc...)