I have a class with an array of pointers that gets dynamically allocated in the constructor. This class also has a function to populate the array.
HolderClass::HolderClass(int number)
{
arrayOfPointers = new ItemClass*[number];
}
HolderClass::addItem(int number, ItemClass item)
{
arrayofPointers[number] = &item;
}
Even though this would compile is my understanding correct in that I would actually be populating the array with dangling pointers since the lifetime of the item variable is only for the duration of the addItem function?
What would be the correct way of populating the arrayOfPointers with pointers to the passed in items? The one complexity here is that there will be child classes of ItemClass that will get passed to the addItem function so I don't believe default copy constructors could be used.
EDIT: This code is for an Arduino so I'm fairly limited in what can and can't be done. This also means that I would like to keep things simply for users of this class (since there are lots of Arduino newbies) and not require them to pass in a pointer to the addItem function (which would require them to manage the life of the passed in ItemClass object).
What would be the correct way of populating the arrayOfPointers with pointers to the passed in items?
Firstly, don't use raw new and delete. Use containers and smart pointers.
struct HolderClass
{
std::unique_ptr<std::unique_ptr<ItemClass>[]> arrayOfPointers;
// ...
};
HolderClass::HolderClass(int number)
{
arrayOfPointers = std::make_unique<std::unique_ptr<ItemClass>[]>(number);
}
Then, pass a pointer to addItem instead of a value to avoid object slicing and lifetime issues:
HolderClass::addItem(int number, std::unique_ptr<ItemClass> item)
{
arrayofPointers[number] = std::move(item);
}
Related
I am working on a project for my University where i have to implement a Hash table. I am quite new to c++, so please forgive me if I am not specific enough or if I have completely wrong assumptions.
Soo..my main problem is that I have a so called "Bucket" which is a struct in my program and which contains a pointer array of N(template parameter) places.
struct Bucket {
T *kptr{ nullptr };
Bucket *bptr{ nullptr }; //For overflow chains (linear Hashing)
Bucket(Bucket *bptr = nullptr) : kptr(new value_type[N]),bptr(bptr) {}
~Bucket() { if(bptr) delete[] bptr; if (kptr) delete[] kptr; }
};
In my main Class named My_Set for example I have an additional Bucket *table of [1<
My first assumption was to initialize the kptr array to nullptr and then in the insert method to make something like
void insert(Bucket &bkt, T &key) {
for (int i=0; i<N, ++i) {
if (bkt.kptr[i]) { //Check on nullptr!
kptr[i] = key;
}
}
}
But that´s not possible because then kptr should be Bucket T **kptr and not Bucket *kptr as far as i understood it.
So, is there any other efficient way to check one single field of an array if it has been assigned to an Object already or not?
IMPORTANT: I am not allowed to use STL Containers, Smart Poitners and similar things which would make the whole thing much easier.
Thanks!
Check whether pointer in pointer array is already “filled”
... So, is there any other efficient way to check one single field of an array if it has been assigned to an Object already or not?
Yes: Initialize the pointer to nullptr. Then, if the pointer has a value other than nullptr, you know that it has been pointed to an object.
However, your professor is correct that your checking is inefficient. On every insert you iterate through all previously inserted objects.
That is unnecessary. You can avoid trying to check whether any of the pointers have been assigned by remembering where the next free pointer is. How can we "remember" things in algorithms? Answer: Using variables. Since you must remember for each instance of your container, you need a member variable.
Since you are using this new variable to remember the next free pointer, how about we name it next_free. Now, considering that the variable must refer to an existing object, what type should it have? A reference would be a good guess, but you must also be able to reassign it once an element is inserted. What can refer to an object like a reference, but can be reassigned? Answer: A pointer. Since this pointer is going to point to a pointer to T, what should be its type? Answer: T**. What should it be initialized to? Answer: The address of the first element of kptr. With such member, insert can be implemented like this:
void insert(T &key) { // why would there be a Bucket argument for insert?
*next_free++ = new T(key); // Note: Do not do this in actual programs. Use
// RAII containers from the standard library instead
}
then kptr should be Bucket T **kptr and not Bucket *kptr as far as i understood it.
Correct. A T* can not point to an array that contains pointers (unless T happens to be a pointer) - it can point to an array of T objects. A T** can point to an array of pointers to T.
Instead of pointers to separately allocated objects, it would be more efficient to use a flat resizable array. But since you are not allowed to use std::vector, you would then have another standard container to re-implement. So consider whether the efficiency is worth the extra work.
Suppose I have the following:
class Map
{
std::vector<Continent> continents;
public:
Map();
~Map();
Continent* getContinent(std::string name);
};
Continent* Map::getContinent(std::string name)
{
Continent * c = nullptr;
for (int i = 0; i < continents.size(); i++)
{
if (continents[i].getName() == name)
{
c = &continents[i];
break;
}
}
return c;
}
You can see here that there are continent objects that live inside the vector called continents. Would this be a correct way of getting the object's reference, or is there a better approach to this? Is there an underlying issue with vector which would cause this to misbehave?
It is OK to return a pointer or a reference to an object inside std::vector under one condition: the content of the vector must not change after you take the pointer or a reference.
This is easy to do when you initialize a vector at start-up or in the constructor, and never change it again. In situations when the vector is more dynamic than that returning by value, rather than by pointer, is a more robust approach.
I would advice you against doing something like the above. std::vector does some fancy way of handling memory which include resizing and moving the array when it is out of capacity which will result in a dangling reference. On the other hand if the map contains a const vector, which means it is guaranteed not to be altered, what you are doing would work.
Thanks
Sudharshan
The design is flawed, as other have pointed out.
However, if you don't mind using more memory, lose the fact that the sequence no longer will sit in contiguous memory, and that the iterators are no longer random access, then a drop-in replacement would be to use std::list instead of std::vector.
The std::list does not invalidate pointers or references to the internal data when resized. The only time when a pointer / reference is invalidated is if you are removing the item being pointed to / referred to.
I have a class storing an multidimensional array as member.
struct Structure
{
Structure()
{
memset(Data, 0, sizeof Data);
}
int Number;
int Data[32][32][32];
}
When I write a function returning an object of this Structure, are all the bytes if the Data member copied or is just a reference passed?
Structure Create(int Parameter)
{
Structure structure;
// modify structure based on parameter
// ...
return structure;
}
If that results in copying the whole block of data, how can I do better? And what would it change to allocate the object on the heap like Structure *structure = new Structure(); and returning that pointer?
When you return the object by value, the actual data (323 ints) will be copied. It's possible the compiler will optimise away the copy (so called "copy elision"), but that is never guaranteed.
If you allocate the object dynamically and return a pointer to it, there will be no copying, of course. If you have access to C++11, consider returning a std::unique_ptr, so that ownership is clear and there's no chance of memory leaks.
In C++11, you could also "do better" by turning the member Data into a conainer (such as std::vector) which internally stores its data on the heap and has move semantics. This means that when returning from a function, the container will be moved instead of copied, and data will not be duplicated.
When you return an object by value the object will not actually be copied, instead your function will populate the object directly in the callers memory. It's as if you did the following:
Structure s;
Create(Parameter, &s);
Although a little better as the default constructor doesn't even get called. This is called "return value optimisation". Although it's not guarenteed by the standard, it is performed by all mainstream C++ compilers (clang, gcc, and Visual C++ all included).
If you want it on the heap then do this:
Structure * Create(int Parameter)
{
Structure * structure = new Structure();
return structure;
}
But it's better to use a smart pointer. If you're using c++11 you can use std::unique_ptr.
std::unique_ptr<Structure> Create(int Parameter)
{
auto structure = std::unique_ptr<Structure>(new Structure());
return structure;
}
You can have it behave however you want. If you define a function like this...
Structure* someFunction();
will return a pointer to a Structure object. This object must be allocated with new. For example defining the function like this:
Structure* someFunction() {
Structure* someNewStructure = new Structure();
return someNewStructure;
}
You have to remember that this element was created within this function, and the function is transferring "responsibility" for the destruction of this object on to the caller. It is usually best to avoid this, though with large data structures it can't be. Another way to handle this is to define a copy constructor in your class so that you can do it the way you referenced. Without defining this copy constructor if you did this:
Sturcture someFunction() {
Structure someResultStruct;
return someResultStruct;
}
When you call someFunction in this case, if your class contained dynamic elements, or other complex data types, they are not guaranteed to copy correctly on return, and you will get weird behavior... unless you define your own copy constructor.
I have a class that is responsible for creating and initializing a number of large objects, as the objects are all of the same Type and I don't want to repeat the same initializing code for all the objects, I call an Init method for each object, for example:
InitObject(objMember);
void Test::InitObject(LargeObject * obj)
{
obj = new LargeObject;
obj->Load();
obj->SetSomeProperty(false);
}
Once this has been done, from a public method I call a set of methods to get a pointer to each of the objects:
//public
LargeObject * Test::GetObject()
{
return objMember;
}
The issue is that the objects are losing scope, when InitObject is called, the objects are correctly constructed and populated, but when I call GetObject, it has lost everything.
I'm probably missing something trivial, but I can't see why it's going out of scope.
It is trivial, yes. You're initializing a copy of the original pointer. You probably want to pass it by reference:
void Test::InitObject(LargeObject*& obj)
Passing by value means that you're assigning the return of new to a copy of the pointer. The one outside the function InitObject remains unchanged.
A few more things - initializing objects after construction should be done with care. If the object isn't valid after construction, it's a bad design (excluding some rare cases). You can signal invalid initialization by throwing an exception from the constructor.
Also, consider using smart pointers instead of raw pointers.
I am trying to erase a vector of pointers that I pass by value into some function. The reason why I pass by value is that I plan to erase these values in numerous calls to the function. So if I pass by pointer/reference I could not achieve this.
First of all is the statement above correct?
Here is some example code:
vector<Boson*>* BosonMaker::remove_duplicates(vector<Boson*>* boson_candidates, vector<Particle*> child_candidates){
vector<Particle*> used_leptons.clear();
// This needs deleting at some point
m_unduplicated_bosons = new vector<Boson*>();
for(int i_b = 0; boson_candidates->size(); i_b++){
vector<Particle*>::iterator child1_finder = find(used_leptons.begin(), used_leptons.end(), boson_candidates->at(i_b)->Child1());
//Search pointer will reach end of collection if child isn't in the used_leptons vector
if (child1_finder == used_leptons.end()) {
vector<Particle*>::iterator child2_finder = find(used_leptons.begin(), used_leptons.end(), boson_candidates->at(i_b)->Child2());
if (child2_finder == used_leptons.end()) {
used_leptons.push_back(boson_candidates->at(i_b)->Child1());
used_leptons.push_back(boson_candidates->at(i_b)->Child2());
// And add the boson to the vector of final bosons
unduplicated_bosons->push_back(boson_candidates->at(i_b));
}
}
}
// Now make a vector of unused leptons
for (int i_l = 0; i_l < used_leptons.size(); i_l++) {
vector<Particle*>::iterator lepton_finder = find(child_candidates.begin(), child_candidates.end(), used_leptons.at(i_l));
child_candidates.erase(lepton_finder);
}
return unduplicated_bosons;
}
I would then use this member function inside the class like so
vector<Boson*> *m_boson_finals_elpair = remove_duplicates(&m_boson_electronPair_candidates, m_all_particle_candidates);
vector<Boson*> *m_boson_finals_mupair = remove_duplicates(&m_boson_muonPair_candidates, m_all_particle_candidates);
vector<Boson*> *m_boson_finals_elneutrino = remove_duplicates(&m_boson_electronNeutrino_candidates, m_all_particle_candidates);
vector<Boson*> *m_boson_finals_muneutrino = remove_duplicates(&m_boson_muonNeutrino_candidates, m_all_particle_candidates);
My question is:
Would m_all_particle_candidates which is
vector<Particle*> m_all_particle_candidates;
be different in each call of remove_duplicates?
I think I am trying to ask is the iterator lepton_finder erased from the vector and not the actual object Particle since I have passed by value?
Note: There was a typo in the remove_duplicate function. I passed by pointer and not value. it should be value
I'm a little confused about what you are saying about passing by value and passing by reference, so I'm going to give a short explanation on that first:
When passing by value, the variable that the method is called with remains unchanged (since a copy is passed into the called method). Be careful though, this case can also incur a heavy performance penalty, since the whole variable is copied! In case of a vector holding many elements this might take quite some time! Passing by value is achieved like this in C++:
When passing by reference (or more or less equivalently by pointer) the outer variable is also changed - since you're only passing a reference into the method, which is referencing the same actual space in memory as the original variable!
So basically what the difference is that in when using call by value, the original caller's value remains unchanged, while when using call by reference, a reference to the original caller's value is passed in, and therefore this value can change on both ends.
Now which method is needed simply depends on what you want to achieve. Pass by Value if the variable you're passing into the method should remain unchanged (m_all_particle_candidates in your example). Or if you need it to change, then pass by reference/pointer.
If the passed-in variable shouldn't change, but you also only need a read-only version of the variable inside the method, then the possible performance problems introduced by passing by value can be overcome by using a const reference. In you case, however, you seem to need a full copy (meaning a normal pass-by-value).
Does the code presented in the OP compile? I don't think so. In fairness, it should be passed through a compiler before posting.
typedef struct {
long double x, y, z;
} V3;
void fnExpectingPtrToVec(vector<V3> * pvec) {
}
void fnExpectingVec(vector<V3> vec) {
}
void testVecs() {
vector<V3> v;
//fnExpectingPtrToVec(v); Does not compile
fnExpectingPtrToVec(&v);
fnExpectingVec(v);
}
If it is expecting a pointer to a vector in the 2nd param, and you passed in a vector instead, then its a compile error.
When you fix the function to accept a vector, not a pointer to one, and call it with your vector it will make a copy and the repeated calls to the function will leave m_all_particle_candidates unchanged.
You're not passing the vector by value.
vector<Boson*>* BosonMaker::remove_duplicates(vector<Boson*>* boson_candidates, vector<Particle*> *child_candidates);
will pass a pointer to the vector by value. But the pointer, which is a copy of the original one, will point to the same vector as the original.
So you're basically changing the same vector as outside the call.
To pass by value, you need:
vector<Boson*>* BosonMaker::remove_duplicates(vector<Boson*> boson_candidates, vector<Particle*> child_candidates);
But be careful when doing so. Copying will occur, so you probably need to override the virtual destructor, copy constructor and assignment operator for Boson and Particle if they're not POD types.