C++ class instances - c++

I am working on intro c++ homework, but I am stuck.
Account *GetAccount(int an);
int main()
{
Account *a1,*a2,*b1;
a1=GetAccount(123);
a2=GetAccount(456);
b1=GetAccount(123);
if(a1==b1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
GetAccount method is supposed to check whether the instance already exists with the same account number, if it does, returns that instance.
Only method I can think of is to create array of Account and search for account, then if it doesn't exist, insert new Account in the array. If it exists, returns the pointer to the array.
This method doesn't really seem efficient to me, and is there any other way?

Yes. Instead of array, use a map. It fill be more efficient in terms of space, and almost as fast.
You can use STL and keep your accounts in a std::map, one of these variants:
map<int, Account> or
map<int, Account*>
In the first case, you keep the Accounts in the map, in the second you keep the pointers to Accounts, and are responsible for creation/deletion. Which variant is more appropriate? it depends on the way you create/initialize the account.
Short tutorial on STL map usage
I will exlain the case when you keep the pointers in the map.
This is how you would declare the map:
map<int, Account*> accounts;
This is how you can add a new account to the map:
int account_id = 123; // or anything else
Account* account = new Account(...paramters for the constructor...)
// any additional code to initialize the account goes here
accounts[account_id] = account; // this adds account to the map
This is how you check if the account with account_id is in the map:
if (accounts.find(account_id) != accounts.end()) {
// It is in the map
} else {
// it is not in the map
}
This is how you get pointer to an account from the map:
Account* ifoundit = accounts[account_id];
Finally, somewhere at the end of your program, you need to clean the map and delete all the account objects. The program will work fine even without the cleanup, but it's important to clean up after yourself. I leave this as an exercise for you :)
Find how to iterate all the elements of the map, and apply delete appropriately.

This method doesn't really seem efficient to me, and is there any other way?
Yes, as others have mentioned, there are more efficient ways using data structures other than arrays. If you've recently been studying arrays and loops in your class, though, the method you describe is probably what your instructor is expecting. I wouldn't try to get too far ahead of your instructor, since the arrays and loop method is probably the sort of thing you'll need to be very familiar with when you take your exams. It's also a good idea to have a strong foundation in the basics before you move forward. (Don't let that deter you from asking more advanced questions on here, though.)

Consider hash tables.

You could use a std::map instead of a simple array.

The method you proposed, an array of ids which you walk through and test, is a very easy one. I would use a std::vector, however, not an array, as you then don't have to worry about size. Otherwise, you just declare a big array, and test that it isn't full when adding.
In terms of efficiency, doing a linear search over a small array (in the hundreds) is quite fast, and may well be faster than other solutions, like maps and sets. However, it does not scale well.
Try to write your code well, but don't worry about optimising it until you know you have a probelem. I would much rather my programmers wrote clean, easy to maintain code than go for optimal speed. We can always speed things up later, if we need to.

Create a std::map of account # => Account object.

Related

How to approximate the size of an std::unordered_map in C++

It is said that an unordered_map<int,int> takes up much more space than a vector<int>. While I am completely aware of that, I would like to know how to get the approximate size of a single instance of an unordered_map in C++. For now, let's say that I inserted n = 1000000 elements into it. I presume that the memory taken up is n multiplied by some kind of constant, I am, however, unable to find an accurate answer anywhere on the Internet. Here is what I'm doing. I'd like to calculate how much memory u_m uses, without writing any code. Is there a way to do that?
#include<bits/stdc++.h>
using namespace std;
const int N = 1000000;
unordered_map<int,int> u_m ;
int main(){
for(int i = 0;i<N;i++){
u_m[i] = 123+i;
}
return 0;
}
If that makes a difference, I intentionally put u_m outside of main
There is no general purpose answer to this. The memory used can vary wildly based on the implementation. To be clear, unordered_map is not tree-based; it's typically implemented as an array of buckets.
But while the spec allows you to know how many buckets are currently in play (via bucket_count) and you can ask for the number of items in each bucket (with bucket_size), there is no way to ask how a bucket is implemented. Based on the various requirements of methods like bucket_size and extract/merge, it's likely a bare bones linked list (bucket_size is allowed to be O(n) in the size of the bucket, so it needn't know its own size directly; extract needs to be able to return a handle that can be transferred between unordered_maps, and merge is guaranteed not to copy or move when moving elements from one unordered_map to another), but the details of implementation are largely hidden.
There's also no guarantee on what is stored in the first place. It could be just key and value, or key, value and hash, or something else.
So while you can get basic info from the various .bucket* APIs, since the contents and implementation of a "bucket" is itself essentially unspecified, you'll never get an answer to "how big is an unordered_map" from any C++ standard APIs; you'd need to know the implementation details and use them alongside the .bucket* APIs, to get an estimate.
An unordered_map is not a tree, it is a hash table. It size is dependent on several things, both on amount you've inserted, but also on things like calling reserve to pre-allocate memory. The specific settings of initial allcoation size and load factors are implementation dependent, so any guess you make will probably differ between compilers, and the order of operations that result in when and by how much the hash table resizes will differ too.

what is the most elegant way of returning a lot of std::map<,>::iterator?

I am working on a car fleet program that has a container that contains a lot of cars
std::map<CarKey, Car> _cars;
I need to write a function/class that operate on a subset of the car objects in the _cars
Naively I can just iterate through _cars with a filter function
for(auto& p : _cars){
//please note: I cannot get things done with one iteration, I have to iterate many times to get things done
if (isOfInterest(p.second)){
// do some thing
}
}
the downside of such a solution is that is I am interested only in 10% of the cars, I will have to waste a lot time iterating
I am trying to find an elegant way to return all the iterators that I am interested
std::vector<std::map<CarKey, Car> :: iterator > getAllIntereted(_cars)
then I can simply iterate through the vector
I am not sure if this is a good approach. Maybe there is some design pattern that can be helpful?
Can anyone give any insights?
Thanks
Without seeing more of the code, I think returning a vector containing pointers to just the cars you are interested in is a good solution. Pointers because otherwise you are creating duplicate objects.
However, if you can just do the work in the same loop that you identify the car, I think that would be best. Just depends on if that is practical.

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.

operator[] - why should I not use it?

I have been told that using the operator[] is wrong.
what is the difference between:
vector<double> * IDs;
...
IDs->operator[](j) = 1;
and:
vector<double> * IDs;
...
(*IDs)[j] = 1;
Nothing at all, they are equivalent.
Two things though
1) IDs->operator[](j) is less clear than (*IDs)[j].
2) If you can use const vector<double>& IDs instead then not only do you benefit from the even clearer IDs[j] but you also gain stability via the fact that you cannot modify the vector using IDs.
Remember that one day your code will be maintained by someone less able than you so clarity is important.
The whole idea of using this operator is so that your object can use the [] in some way that hides the real data structure or data organization within itself but on the outside, provides an array-like interface.
For e.g. both vectors and deques are implemented quite differently and have better performances for different purposes, but on the outside, they both provide the [] so that the user feels like he's using a dynamic array.
So, it's not wrong, but it defeats the purpose.

Vector versus dynamic array, does it make a big difference in speed?

Now I am writing some code for solving vehicle routing problems. To do so, one important decision is to choose how to encode the solutions. A solution contains several routes, one for each vehicle. Each route has a customer visiting sequence, the load of route, the length of route.
To perform modifications on a solution the information, I also need to quickly find some information.
For example,
Which route is a customer in?
What customers does a route have?
How many nodes are there in a route?
What nodes are in front of or behind a node?
Now, I am thinking to use the following structure to keep a solution.
struct Sol
{
vector<short> nextNode; // show what is the next node of each node;
vector<short> preNode; //show what is the preceding node
vector<short> startNode;
vector<short> rutNum;
vector<short> rutLoad;
vector<float> rutLength;
vector<short> rutSize;
};
The common size of each vector is instance dependent, between 200-2000.
I heard it is possible to use dynamic array to do this job. But it seems to me dynamic array is more complicated. One has to locate the memory and release the memory. Here my question is twofold.
How to use dynamic array to realize the same purpose? how to define the struct or class so that memory location and release can be easily taken care of?
Will using dynamic array be faster than using vector? Assuming the solution structure need to be accessed million times.
It is highly unlikely that you'll see an appreciable performance difference between a dynamic array and a vector since the latter is essentially a very thin wrapper around the former. Also bear in mind that using a vector would be significantly less error-prone.
It may, however, be the case that some information is better stored in a different type of container altogether, e.g. in an std::map. The following might be of interest: What are the complexity guarantees of the standard containers?
It is important to give some thought to the type of container that gets used. However, when it comes to micro-optimizations (such as vector vs dynamic array), the best policy is to profile the code first and only focus on parts of the code that prove to be real -- rather than assumed -- bottlenecks.
It's quite possible that vector's code is actually better and more performant than dynamic array code you would write yourself. Only if profiling shows significant time spent in vector would I consider writing my own error-prone replacement. See also Dynamically allocated arrays or std::vector
I'm using MSVC and the implementation looks to be as quick as it can be.
Accessing the array via operator [] is:
return (*(this->_Myfirst + _Pos));
Which is as quick as you are going to get with dynamic memory.
The only overhead you are going to get is in the memory use of a vector, it seems to create a pointer to the start of the vector, the end of the vector, and the end of the current sequence. This is only 2 more pointers than you would need if you were using a dynamic array. You are only creating 200-2000 of these, I doubt memory is going to be that tight.
I am sure the other stl implementations are very similar. I would absorb the minor cost of vector storage and use them in your project.