I've hit a bit of a hurdle with creating objects using user input for variables. Basically the program determines what type of object the user wants, creates it, and then asks if the user wants to add another object. In this example the object is a manager, which is a subclass of employee.
void add_manager()
{
string name;
//Performs a bunch of checks to ensure the input is valid.
name = get_string_input("Please input the name of the employee.");
//Creates a manager object.
manager manager1(name);
//Goes back to previous function, restarts process of finding out employee type.
ask_employee();
}
I will be storing pointers to each object in a dynamic array elsewhere. The point of the array is just to get values out of each object to use in some printouts, so I was expecting to just loop over the array, get the value of each, and print. (Rough example)
The part I'm not sure about is how to change the object constructor call so the objects are made as manager1, manager2 etc. There will be a varied number made due to what the user wants, and I was hoping to keep them in a way to tell the difference.
Since I will be accessing the objects via pointers, do the object names even need to be different? Or can objects and pointers all have the same name?
Since managers objects can be in an infinite number, you can't name them all. C++ is a statically typed language. You strictly need to keep your manager objects in an array-like structure:
std::vector<manager *> vManagers;
void add_manager()
{
string name;
//Performs a bunch of checks to ensure the input is valid.
name = get_string_input("Please input the name of the employee.");
//Creates a manager object.
vManagers.push_back(new manager(name));
//Goes back to previous function, restarts process of finding out employee type.
while(ask_employee()
{
name = get_string_input("Please input the name of the employee.");
vManagers.push_back(new manager(name));
}
}
So that when you need manager object you can call:
vManagers[n]->GetData();
But note that you need to delete manager object pointers in apppriate places to avoid leaks:
delete vManagers[n];
vManagers[n] = NULL;
Do the object names even need to be different?
They don't need to be different, when you store them in the array there is no connection between the objects and their names, e.g. they can be all instantiated using manager11. (Additionally, you can't use their name for search.)
What differentiates the objects are the values of their data members. Thus, if you want to search the objects define an object id or name as data member and then you can use it in your search criterion to find a particular manager.
Edit 1:
One way to create an object counter is by defining a data member:
static int counter = 0;. Then you increment your counter in the constructor to reflect object instantiation and decrement it in the destructor.
Edit 2:
If you want to store objects it would be better to use vector<object_type> container_name (instead of arrays). To do this you need to define a vector outside the object you want to store. In case of storing pointers to type object_type, you can do something like:
vector<object_type*> container_name;
object_type* ObjectInstance = new object_type(parameters);
// store in vector
container_name.emplace_back(ObjectInstance);
1.The names you give variables are available to the program only at compile time, when you turn it from source into an executable file. Afterwards, when you want to create objects , those kinds of information are no longer available. The program only knows about the machine addresses where operands to machine instructions are located.
Related
Is it possible to get all variables in memory by type?
Example:
string container[]; //Array that will contain the objects
GetAllObjects(string, &container); //Get all the objects by specified object type
No, not generally.
If the objects itself maintain a list of them, ie. the constructor adds it´s own object to some global array/list and the destructor removes it, then yes. But without changes to the class, it isn´t possible.
If you plan to implement such a list thing, pay attention to multi-thread locking.
I have a class myClass. A myClass object has a (human readable) name, and some more information.
class myClass
{
std::string name;
int attribute;
int anotherAttribute;
}
They are stored inside a STL container, a vector, for example.
std::vector<myObject> myList;
When the client wants to access an element, it does this by name. That means, I have to iterate over the whole vector to find the correct object (the container contains about a few hundred objects).
So, I'm thinking of moving to std::map as container, instead of vector. As far as my understanding is, a map should be the container of choice when accessing elements by name, instead of an index.
However, then the name of the object is stored twice, once as the map key, and in the object itself. The memory overhead should be no problem, but I wonder if this is good practise. There may be the problem that the names run out of sync (for some mysterious reason). I even thought about dropping the name member of myClass.
To make it short: what container should I use, and why?
You should choose your container based on the way your store and access data in it. So in your usecase you should definitely use a unordered_map
You should keep the std::string name attribute in your class if and only if you use it from inside the class.
So the question is will you at any point have to get the name from the object, rather than the object from its name.
This occurs when you get the object from the container and store it elsewhere, then use it later on.
Given the nature of name (which is most likely not going to change) you don't really have to worry about the name attribute not being "in sync" with the key you use in the unordered_map
If memory isn't a primary concern I'd advise you to keep it.
I am attempting to construct a bunch of objects that can share data, but aren't coupled to each other. What I want is for the fields of each object to be a shared_ptr to whatever data they need. Once all the objects are created, this will fulfill all my needs, but my issue is how to distribute the information needed to create the shared_ptr's, since the types can be anything.
I will be creating all objects that share a set of data at once inside a factory object. Also, each shared field will have an enum entry to signify the attribute type (not data type). For instance the enum will have an entry that is Position, and every object that needs position information will use enum to key into a map to find the information it needs to create the shared_ptr.
What I want from my system is this:
Pass an SetEnum to the factory, which defines which "set" of objects to create, along with an optional map<AttributeEnum, ??> that defines the initial data of set of objects
Create the necessary objects, using a map<AttributeEnum, ??> to create shared_ptr's as fields in each of the objects. If the object needs a field corresponding to a specific value of AttributeEnum, it will pull its value from the map. If that value is not a key in the map, it will create it with a default value, and add it to the map for future objects to use. This step can be done during or after construction if a method with a template type would be helpful to solve the issue.
The issue is that I want errors at compile time, not run time. How can I map AttributeEnum to a type? For example, every field corresponding to an AttributeEnum value of Position will have type shared_ptr<double>, but I want a compile error if I attempt to associate Position with, for instance, shared_ptr<int>. My question is how to go about this?
A couple different systems I have thought of (albeit none of them ensure the errors at compile time):
Pass around a std::map<Enum, shared_ptr<void> > and static cast the shared_ptr's to the appropriate types.
Construct the objects, then iterate through the Enum, checking each object for which attributes it needs, then passing the proper pointers to it.
Having one object "own" each attribute, and force the other to get the information via a message-passing system.
I am considering storing two parallel sets of data, the AttributeEnum having entry Position, and compiler constants that would define the types such as #define POSITION double, then I would simply use POSITION for the type where ever I must, but this would make the code much harder to read.
I've got several objects and need to generate a unique identifier for them which will not be changed/repeated during the lifetime of each object.
Basically I want to get/generate a unique id for my objects, smth like this
int id = reinterpret_cast<int>(&obj);
or
int id = (int)&obj;
I understand the codes above are bad ideas, as int might not be large enough to store the address etc.
So whats the best practice to get a unique identifier from the object, which will be a portable solution ?
Depending on your "uniqueness"-requirements, there are several options:
If unique within one address space ("within one program execution") is OK and your objects stay where they are in memory then pointers are fine. There are pitfalls however: If your objects live in containers, every reallocation may change your objects' identity and if you allow copying of your objects, then objects returned from some function may have been created at the same address.
If you need a more global uniqueness, for instance because you are dealing with communicating programs or data that is persistent, use GUIDs/UUIds, such as boost.uuid.
You could create unique integers from some static counter, but beware of the pitfalls:
Make sure your increments are atomic
Protect against copying or create your custom copy constructors, assignment statements.
Personally, my choice has been UUIDs whenever I can afford them, because they provide me some ease of mind, not having to think about all the pitfalls.
If the objects need to be uniquely identified, you can generate the unique id in the constructor:
struct Obj
{
int _id;
Obj() { static int id = 0; _id = id++; }
};
You'll have to decide how you want to handle copies/assignments (same id - the above will work / different id's - you'll need a copy constructor and probably a static class member instead of the static local variable).
When I looked into this issue, I fairly quickly ended up at the Boost UUID library (universally unique identifier, http://www.boost.org/doc/libs/1_52_0/libs/uuid/). However, as my project grew, I switched over to Qt's GUID library (globally unique identifier, https://doc.qt.io/qt-5/quuid.html).
A lesson learned for me though was to start declaring your own UUID class and hide the implementation so that you can switch to whatever you find suitable later on.
I hope that helps.
If your object is a class then you could have a static member variable which you intestinal to 0. Then in the constructor you store this value into the class instance and increment the static variable:
class
Indexed
{
public:
Indexed() :
m_myIndex( m_nextIndex++ )
{ }
int getIndex() const
{ return m_myIndex; }
private:
const int m_myIndex;
static int m_nextIndex;
};
If you need unique id for distributed environment use boost::uuid
It does not look like a bad idea to use the object address as the unique (for this run) identifier, directly. Why to cast it into integer? Just compare pointers with ==:
MyObject *obj1, *obj2;
...
if (obj1 == obj2) ...
This will not work, of course, if you need to write IDs to database or the like. Same values for pointers are possible between runs. Also, do not overload comparison operator (==).
I'm trying to avoid declaring enums or using strings. Although the rationale to do so may seem dubious, the full explanation is irrelevant.
My question is fairly simple. Can I use the address of a member variable as a unique ID?
More specifically, the requirements are:
The ID won't have to be serialised.
IDs will be protected members - only to be used internally by the owning object (there is no comparison of IDs even between same class instances).
Subclasses need access to base class IDs and may add their new IDs.
So the first solution is this:
class SomeClass
{
public:
int mBlacks;
void AddBlack( int aAge )
{
// Can &mBlacks be treated as a unique ID?
// Will this always work?
// Is void* the right type?
void *iId = &mBlacks;
// Do something with iId and aAge
// Like push a struct of both to a vector.
}
};
While the second solution is this:
class SomeClass
{
public:
static int const *GetBlacksId()
{
static const int dummy = 0;
return &dummy;
}
void AddBlack( int aAge )
{
// Do something with GetBlacksId and aAge
// Like push a struct of both to a vector.
}
};
No other int data member of this object, and no mBlacks member of a different instance of SomeClass in the same process, has the same address as the mBlacks member of this instance of SomeClass. So you're safe to use it as a unique ID within the process.
An empty base class subobject of SomeClass could have the same address as mBlacks (if SomeClass had any empty base classes, which it doesn't), and the char object that's the first byte of mBlacks has the same address as mBlacks. Aside from that, no other object has the same address.
void* will work as the type. int* will work too, but maybe you want to use data members with different types for different ids.
However, the ID is unique to this instance. A different instance of the same type has a different ID. One of your comments suggests that this isn't actually what you want.
If you want each value of the type to have a unique ID, and for all objects that have the same value to have the same ID, then you'd be better of composing the ID from all of the significant fields of the object. Or just compare objects for equality instead of their IDs, with a suitable operator== and operator!=.
Alternatively if you want the ID to uniquely identify when a value was first constructed other than by copy constructors and copy assignment (so that all objects that are copies of the same "original" share an ID), then the way to do that would be to assign a new unique ID in all the other constructors, store it in a data member, and copy it in the copy constructor and copy assignment operator.
The canonical way to get a new ID is to have a global[*] counter that you increment each time you take a value. This may need to be made thread-safe depending what programs use the class (and how they use it). Values then will be unique within a given run of the program, provided that the counter is of a large enough type.
Another way is to generate a 128 bit random number. It's not theoretically satisfying, but assuming a decent source of randomness the chance of a collision is no larger than the chance of your program failing for some unavoidable reason like cosmic ray-induced data corruption. Random IDs are easier than sequential IDs when the sources of objects are widely distributed (for example if you need IDs that are unique across different processes or different machines). You can if you choose use some combination of the MAC address of the machine, a random number, the time, a per-process global[*] counter, the PID and anything else you think of and lay your hands on (or a standard UUID). But this might be overkill for your needs.
[*] needn't strictly be global - it can be a private static data member of the class, or a static local variable of a function.