Problems with updating a vector of pointers in a constructor - c++

stackoverflow!
For my latest assignment, I came across a problem I can't really wrap my head around.
The idea behind it is really easy, you have a basic class called Dir_or_File, which represents (as the name suggests) a directory or a file. Every one of these has two variables within itself, it has a name which corresponds to its path and entries, which consists of a vector, which keeps track of all the directories or files, which are contained in my directory.
To aid in this, I have made a method called split_after_slash, which converts any string into a vector of strings, which are split after each slash, "o1/o2/o3/" becomes a vector with the entries "o1/", "o2" and "o3". This method has been tested and it works as intended. Just for clarification, as I will be using it later on.
With this in mind, the constructor is causing problems, the idea is, that I give a path (as a string) to my constructor and it will initiate a directory.
For example:
Dir_or_File dir("/home/music/song.mp3");
Should create the Dir_or_File object "dir", which consists of its name, which is "/home/music/song.mp3" and a vector named entries, which would itself contain a Dir_or_File with the name"home/music/song.mp3" and entrieswith a Dir_or_File with the name "music/song.mp3" in it and so on. At the end, you would have your last entry, named "song.mp3", which has an empty list of entries.
My idea is to solve said problem via recursion, which I tried the following way:
Dir_or_File::Dir_or_File(std::string name)
{
this->name = name;
std::vector<std::string> full_path = split_after_slash(name);
if (full_path.size() > 1)
{
std::string new_param;
for (unsigned int i = 1; i < full_path.size(); i++)
{
new_param.append(full_path[i]);
}
Dir_or_File new_entry(new_param);
entries.push_back(&new_entry);
}
}
Setting the nameis self-explainatory, splitting the string should be too. After that, I only need to know if there is more than one string remaining in the path, which means I would be in a folder, which still has a sub-folder, if there is a sub-folder, I will call the constructor with everything but the folder I'm currently in, if there is no sub-folder, I don't need to add any entries to, well entries.
But if I test my code now, I can create a Dir_or_File, which has one entry in entries, but thats it, the entry has no name, but some gibberish and an empty entries vector, what am I doing wrong here?

Is this something that is fundamentally wrong with my approach or something that can be fixed?
Yes. Yes.
The lines
Dir_or_File new_entry(new_param);
entries.push_back(&new_entry);
are the source of your problems. new_entry is a local variable in the function. Storing its address in entries is not good. When the function returns, entries will contain a list of dangling pointers.
You can fix the problem using couple of approaches.
Make entries a vector of objects instead of vector of pointers. Then, you can use
entries.push_back(new_entry);
Allocate dynamic memory using new and store the pointer in entries.
Dir_or_File* new_entry = new Dir_of_File(new_param);
entries.push_back(new_entry);
Note that, if you use the second approach, you'll have to write a bunch of booking code to manage pointers. It will be easier to user the first approach, which will also result in less buggy code.
You can store smart pointers in stead of raw pointers in entries but even that requires you to understand how to smart pointers. The first approach is still better, IMO.

Related

When/where are global element ID's assigned when creating parts using Exodus?

I have a finite element part, made up of hexahedrals. I am writing it out to an Exodus file format so it can be viewed in Paraview.
Basic things like the name of the part and connectivities of the elements and areas of their faces works fine. For example, to write out the name, I can do:
ex_put_name( fileId, EX_ELEM_BLOCK, blockIndex, name.data() )
Where name is some std::string.
However, I am running into an issue with the Global Element IDs variable. This seems to be automatically created by Exodus on creation of the part.
Is there some way to modify these global element ID's?
OR, is there some way to incrementally add elements to the file, rather than in blocks?
Sometimes the blocks aren't contiguous, and thus the global element ID's no longer line up with the original mesh's IDs.
Example. Here is a mesh colored by global element ID with values I expect:
And here is that same mesh, but with blocks that are not contiguous. The global element IDs are no longer correct!
I could just add another variable which really is the global element IDs, and call it "Real Global Element IDs" or something, but that's really kludgy. Or make every single element into its own block, but that's also awful.
Note: I would add the tag "ExodusII" since that's really what I'm asking about, but lack the reputation. Sorry for any confusion.

Create dynamic array of objects

I want to create a dynamic array of a specific object that would also support adding new objects to the array.
I'm trying to solve this as part of an exercise in my course. In this exercise we are not supposed to use std::vector.
For example, let's say I have a class named Product and declare a pointer:
Products* products;
then I want to support the following:
products = new Product();
/* code here... */
products[1] = new Product(); // and so on...
I know the current syntax could lead to access violation. I don't know the size of the array in advance, as it can change throughout the program.
The questions are:
How can I write it without vectors?
Do I have to use double pointers (2-dimension)?
Every time I want to add a new object, do I have to copy the array to the new array (with +1 size), and then delete the array?
You should not write this without std::vector. If you for some reason need to, your copying with every resize is by far the easiest option.
I do not see how that would help. (I.e. no)
As mentioned above, this is by far the easiest method if you cannot use std::vector. Everything else would be (partially) reinventing one standard library container or the other, which is hard.
You have to use your own memory memory management, i.e. more specifically wrt your other (related) questions:
No, if you have a contiguous allocated chunk of memory where your data lives in.
Yes, if 2. is your desired implementation method. However, if you don't want to use a large memory chunk, you have to use a (double) linked list which does not require you to copy the whole array every time.
I see people already answered your specific questions, so I'll answer a more general answer.
You must implement a way to do it by yourself, but there are lots of Abstract Data Types that you can use, as far as I can see the simplest would be a linked list, such as the following:
class ProductNode
{
public:
ProductNode() : _data(NULL), _next(NULL)
{
}
void setProduct(Product* p); //setter for the product pointer
{
this->_data = p;
}
Product getProduct(); //getter for the product pointer
{
return *(this->_data);
}
void addNext(); //allocate memory for another ProductNode in '_next'
{
if(!next)
{
this->_next = new ProductNode();
}
}
ProductNode* getNext(); //get the allocated memory, the address that is in '_next'
{
return this->_next;
}
~ProductNode(); //delete every single node from that node and forward, it'll be recursive for a linked list
private:
Product* _data;
ProductNode* _next;
}
Declare a head variable and go from there.
Of course that most of the functions here should be implemented otherwise, it was coded quickly so you could see the basics that you need for this assignment.
That's one way.
Also you can make your own data type.
Or use some others data types for abstraction of the data.
What you probably should do (i.e. what I believe you're expected to do) is write your own class that represents a dynamic array (i.e. you're going to reinvent parts of std::vector.)
Despite what many around here say, this is a worthwhile exercise and should be part of a normal computer science curriculum.
Use a dynamically allocated array which is a member of your class.
If you're using a dynamically allocated array of Product*, you'll be storing a Product**, so yes, in a way. It's not necessary to have "double pointers" for the functionality itself, though.
Technically no - you can allocate more than necessary and only reallocate and copy when you run out of space. This is what vector does to improve its time complexity.
Expanding for each element is a good way to start though, and you can always change your strategy later.
(Get the simple way working first, get fancy if you need to.)
It's probably easiest to first implement an array of int (or some other basic numerical type) and make sure that it works, and then change the type of the contents.
I suppose by "Products *products;" you mean "Products" is a vector-like container.
1) How can I write it without vectors?
As a linked list. Instantiating a "Products products" will give you an empty linked list.
Overriding the operator[] will insert/replace the element in the list. So you need to scan the list to find the right place. If several elements are missing until you got the right place, you may need to append those "neutral" elements before your element. Doing so, through "Product *products" is not feasible if you plan to override the operator[] to handle addition of elements, unless you declare "Products products" instead
2) Do I have to use double pointers (2-dimension)?
This question lacks of precision. As in "typedef Product *Products;" then "Products *products" ? as long as you maintained a " * " between "Products" and "products", there is no way to override operator[] to handle addition of element.
3) Every time I want to add a new object, do I have to copy the array to the new array (with +1 size), and then delete the array?
If you stick with array, you can use a O(log2(n)) time reallocation, by simply growing twice the array size (and supposedly you have a zero-terminal or a count embedded). Or just use a linked list instead to avoid any copy of all elements before adding an element.

C++ Deleting objects from memory

Lets say I have allocated some memory and have filled it with a set of objects of the same type, we'll call these components.
Say one of these components needs to be removed, what is a good way of doing this such that the "hole" created by the component can be tested for and skipped by a loop iterating over the set of objects?
The inverse should also be true, I would like to be able to test for a hole in order to store new components in the space.
I'm thinking menclear & checking for 0...
boost::optional<component> seems to fit your needs exactly. Put those in your storage, whatever that happens to be. For example, with std::vector
// initialize the vector with 100 non-components
std::vector<boost::optional<component>> components(100);
// adding a component at position 15
components[15].reset(component(x,y,z));
// deleting a component at position 82
componetnts[82].reset()
// looping through and checking for existence
for (auto& opt : components)
{
if (opt) // component exists
{
operate_on_component(*opt);
}
else // component does not exist
{
// whatever
}
}
// move components to the front, non-components to the back
std::parition(components.begin(), components.end(),
[](boost::optional<component> const& opt) -> bool { return opt; });
The short answer is it depends on how you store it in memmory.
For example, the ansi standard suggests that vectors be allocated contiguously.
If you can predict the size of the object, you may be able to use a function such as size_of and addressing to be able to predict the location in memory.
Good luck.
There are at least two solutions:
1) mark hole with some flag and then skip it when processing. Benefit: 'deletion' is very fast (only set a flag). If object is not that small even adding a "bool alive" flag can be not so hard to do.
2) move a hole at the end of the pool and replace it with some 'alive' object.
this problem is related to storing and processing particle systems, you could find some suggestions there.
If it is not possible to move the "live" components up, or reorder them such that there is no hole in the middle of the sequence, then the best option if to give the component objects a "deleted" flag/state that can be tested through a member function.
Such a "deleted" state does not cause the object to be removed from memory (that is just not possible in the middle of a larger block), but it does make it possible to mark the spot as not being in use for a component.
When you say you have "allocated some memory" you are likely talking about an array. Arrays are great because they have virtually no overhead and extremely fast access by index. But the bad thing about arrays is that they aren't very friendly for resizing. When you remove an element in the middle, all following elements have to be shifted back by one position.
But fortunately there are other data structures you can use, like a linked list or a binary tree, which allow quick removal of elements. C++ even implements these in the container classes std::list and std::set.
A list is great when you don't know beforehand how many elements you need, because it can shrink and grow dynamically without wasting any memory when you remove or add any elements. Also, adding and removing elements is very fast, no matter if you insert them at the beginning, in the end, or even somewhere in the middle.
A set is great for quick lookup. When you have an object and you want to know if it's already in the set, checking it is very quick. A set also automatically discards duplicates which is really useful in many situations (when you need duplicates, there is the std::multiset). Just like a list it adapts dynamically, but adding new objects isn't as fast as in a list (not as expensive as in an array, though).
Two suggestions:
1) You can use a Linked List to store your components, and then not worry about holes.
Or if you need these holes:
2) You can wrap your component into an object with a pointer to the component like so:
class ComponentWrap : public
{
Component component;
}
and use ComponentWrap.component == null to find if the component is deleted.
Exception way:
3) Put your code in a try catch block in case you hit a null pointer error.

What are some good methods to replace string names with integer hashes

Usually, entities and components or other parts of the game code in data-driven design will have names that get checked if you want to find out which object you're dealing with exactly.
void Player::Interact(Entity *myEntity)
{
if(myEntity->isNearEnough(this) && myEntity->GetFamilyName() == "guard")
{
static_cast<Guard*>(myEntity)->Say("No mention of arrows and knees here");
}
}
If you ignore the possibility that this might be premature optimization, it's pretty clear that looking up entities would be a lot faster if their "name" was a simple 32 bit value instead of an actual string.
Computing hashes out of the string names is one possible option. I haven't actually tried it, but with a range of 32bit and a good hashing function the risk of collision should be minimal.
The question is this: Obviously we need some way to convert in-code (or in some kind of external file) string-names to those integers, since the person working on these named objects will still want to refer to the object as "guard" instead of "0x2315f21a".
Assuming we're using C++ and want to replace all strings that appear in the code, can this even be achieved with language-built in features or do we have to build an external tool that manually looks through all files and exchanges the values?
Jason Gregory wrote this on his book :
At Naughty Dog, we used a variant of the CRC-32 algorithm to hash our strings, and we didn't encounter a single collision in over two years of development on Uncharted: Drake's Fortune.
So you may want to look into that.
And about the build step you mentioned, he also talked about it. They basically encapsulate the strings that need to be hashed in something like:
_ID("string literal")
And use an external tool at build time to hash all the occurrences. This way you avoid any runtime costs.
This is what enums are for. I wouldn't dare to decide which resource is best for the topic, but there are plenty to choose from: https://www.google.com/search?q=c%2B%2B+enum
I'd say go with enums!
But if you already have a lot of code already using strings, well, either just keep it that way (simple and usually enough fast on a PC anyway) or hash it using some kind of CRC or MD5 into an integer.
This is basically solved by adding an indirection on top of a hash map.
Say you want to convert strings to integers:
Write a class wraps both an array and a hashmap. I call these classes dictionaries.
The array contains the strings.
The hash map's key is the string (shared pointers or stable arrays where raw pointers are safe work as well)
The hash map's value is the index into the array the string is located, which is also the opaque handle it returns to calling code.
When adding a new string to the system, it is searched for already existing in the hashmap, returns the handle if present.
If the handle is not present, add the string to the array, the index is the handle.
Set the string and the handle in the map, and return the handle.
Notes/Caveats:
This strategy makes getting the string back from the handle run in constant time (it is merely an array deference).
handle identifiers are first come first serve, but if you serialize the strings instead of the values it won't matter.
Operator[] overloads for both the key and the value are fairly simple (registering new strings, or getting the string back), but wrapping the handle with a user-defined class (wrapping an integer) adds a lot of much needed type safety, and also avoids ambiguity if you want the key and the values to be the same types (overloaded[]'s wont compile and etc)
You have to store the strings in RAM, which can be a problem.

How to store the values of element values but it is referencing final address

when i am storing data into an array after performing parsing an xml file we have to store it in an array but here it stores like the final address of xml file i.e. it stores all the values but the problem is it all values are referencing to one address so i used vector now for getting all the values, so is there any possibility to get all the values without using any predefined methods.
My code is like,
while(attr){
if(!xmlStrcmp(attr->name,(const xmlChar *)"user")){
sprintf((char *)UserName.c_str(),"%s",attr->children->content);
std::cout<<"UserName: "<<UserName.c_str()<<"\t\t";
UN.push_back(UserName.c_str());
}
if(!xmlStrcmp(attr->name,(const xmlChar *)"password")){
sprintf((char *)Password.c_str(),"%s",attr->children->content);
std::cout<<"Password: "<<Password.c_str()<<std::endl;
PWD.push_back(Password.c_str());
}
attr=attr->next;
}
even vectors also, i am getting same problem so how can i solve this.
I think the problem is that you are storing values somewhere in a vector that aren't supposed to be stored permanently. In particular, this line:
UN.push_back(UserName.c_str());
Seems to be storing the result of UserName.c_str() into a vector<const char*>. If you do this, then you'll run into trouble as soon as you modify the UserName string, or when that string goes out of scope. The value of c_str() is pretty fragile - it's not valid after doing just about anything to the source string - and exists primarily so that you can take string data and pass it into C code that needs a const char* as an argument.
To fix this, I would suggest either explicitly copying the strings before inserting them into the vector:
UN.push_back(strdup(UserName.c_str());
(You don't have to use strdup here; it's just an example)
Alternatively, consider storing std::strings in the vector, which own the string resource they point at and don't have this problem.
Hope this helps!