Actually, I want to pass an object to function by taking input from User. There are many objects and I want user to tell which object to pass. One way that I can think of is by using if/else-if statements (e.g if user says 1(int) then it means object-1). But is there any direct method by which I can directly take object as input. So I can pass it to function without using if/else-if statements.
You cannot have a user input an object directly out-of-the-box, but you can certainly write code to obtain that result (for example by implementing deserialization and receiving a JSON representation of the object).
However, if I understood your question correctly, you have a predefined set of objects with known integer keys. In that case, the most straightforward way is to store these objects in a container, such as std::map<int, YourObject> (or an std::vector<YourObject> if your keys are easily mappable to [0;N)). Once you've had the user input the key, you can then lookup into the container to retrieve the corresponding object via the container's at() member function.
Related
I see little use of std::unordered_set or any hash table for that matter if the objects themselves are the keys: in order to search anything, you'd need to have the element in the first place. But if I already have the element, I don't need to search it (the exception being if I only need to check if it's a duplicate).
Much more interesting is the so called "heterogeneous lookup", the case where your data is an object containing multiple pieces of data, and treating one of those as key. For example I want to get all the employee data of one employee named "Pete Johnson" by doing auto it = employees.find("Pete Johnson").
I read about transparent comparators and tried creating my own hash function and 'equal_to' operator to use a subset of the data. Creating the set and adding objects works, but I still cannot get the 'find' function to work the way I want.
The easy solution for what I want is to just use std::unordered_map, but I hoped there would be a better way than to keep two copies of each key. Another workaround is to create a dummy object, copy the key into the dummy, then use that to do the lookup. However, I think the ideal solution would be if I had the option to provide a 'getKey' function to the constructor, so that 'find' can accept a naked key and use 'getKey' to compare it to the object to see if it matches.
std::string getKey(const userData_t& object){
return object.name;
}
std::size_t userData_t_hash(const userData_t& object){
return std::hash<std::string>()(getKey(object));
}
bool userData_t_equals_to(const userData_t& object, const std::string& str){
return getKey(object) == str;
}
bool userData_t_equals_to(const userData_t& object, const userData_t& other){
return getKey(object) == getKey(other);
}
Why would I need to search and obtain (a reference to) the object from the hash table if I already had the object?
One reason is to find out if the object is in the hash table. Sometimes sets are used to eliminate duplicates from a collection. If sorting is not needed, then unordered_set might be the best choice for the task.
It would make more sense if I could provide a 'getKey' function [etc.]
You can in principle. The syntax is not exactly what you had in mind, but the functionality is available.
The hash of an object does not need to take into account all data in the object. The requirement is that if two objects should be considered the same, then they must have the same hash. If you define the hash of your object to be the hash of object.getKey() and define equality to be having the same key, then you could find a real object by constructing a dummy object with just the key set. If your objects represent employees and the key is the name (not the best choice, but sufficient for now), then you could construct an employee object with no data set other than the name, and use that to find the real employee object.
Admittedly, constructing a dummy object to set one field is a bit of a hassle. Hence, C++14 introduced find overloads that accept data that compares equivalent to elements of your set. This requires that the hash and compare types have a member type named is_transparent. For example, this member type exists in std::equal_to<void> (which is not the same as the default comparison, std::equal_to<Key>). With the appropriate hash and comparison definitions, you could use employees.find("Pete") to find the employee object whose name is "Pete".
(I'm going to leave further details as "out of scope" for the question that was asked. Some general information can be found in What are transparent comparators?.)
So one use case for unordered_set is a replacement for unordered_map when the values would necessarily contain the key and the values do not need to change.
In C++ the indexing operator is defined for std::map and std::unordered_map so that if your reference to the container is non-const just the act of indexing without assigning is enough to have implicitly created a value inside the container. This sometimes creates subtle bugs, where you expect to be referencing a value inside a container but instead actually create one, e.g. config["stting"] instead of config["setting"].
I know Python addresses this by having __setitem__ and __getitem__ be separate methods but this requires cooperation with the parser.
Does Rust do anything to address this frequent source of bugs?
No Rust doesn't have that problem. There's no implicit creation of items in Rust collections.
For example you'd insert a key-value pair to a std::collections::HashMap with map.insert(key, value) and retrieve a value with let value = map.get(key);.
Note that .get() will return an Option<&V>, so if the key didn't exist you will get None as a result.
Rust also offers an easy way to either retrieve a value or to insert some default value for the given key if the value doesn't exist with:
let value = map.entry(key).or_insert(0);
HashMap also implements the Index trait, which allows retrieval of a value with let value = map[key];, which will panic if key doesn't exist in map.
Note that because HashMap does not implement IndexMut, this [ ] bracket syntax always returns an immutable reference to the value, so you cannot insert or modify values this way.
I have a C++ API with a C wrapper. A C client can get a handle to an underlying C++ object and then use that to get other information about the object, e.g.
PersonHandle handle = createPerson("NisseIHult");
char* name = getPersonName(handle); //Get person takes a void* pointer
In the code above, the handle is casted to a C++ Person class object.
Question is, how can I check inside getPersonName that the argument, handle, is a valid handle? For example, if a client does this:
char* name = getPersonName(1234);
it will cause an access violation inside getPersonName. I need a way to check and validate the handle, and in the case above, return NULL?
Since handles are pointers to C++ objects, there is no reliable way to check their validity without triggering some undefined behavior.
I have seen two solutions to this problem:
Make handles integers for full control - rather than giving out pointers, keep pointers internally - say, in an unordered map from int to a pointer, along with some metadata, and give users integers to use as handles. This introduces an additional hash lookup in the process of accessing a person, but you can make this perfectly reliable, because all ints are under your control. For example, if you give out handles to objects of different types, you could produce a detailed error message, e.g. "a handle to a Horse object has been used where a Person handle is required". This solution has an additional advantage that you don't have dangling references: a user can pass a handle that you have invalidated, but you can quickly tell that the object is deleted.
Derive all objects to which you give handles from a common base class, and put a "magic number" into the first member of that class - A "magic number" is a bit pattern that you put, say, in an int, and set it in each Person object. After the cast you can check if (personFromHandle->magic != 0xBEEFBEEF) ... to see if the pattern is there. This solution is common, but I would recommend against it, because it has undefined behavior when an invalid handle is passed. It's not OK to use it if the operation is to continue after a failed attempt to use a handle. This solution would also break if passed a reference to a deallocated object.
Similar to the first part of the answer above, put the address of every object you hand out into a std::set (or similar container) and test for existence in the set before casting.
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 create something like a list of functors (functions pointers). Then I write them in binary form into file. The problem is, that, functor - is a simple function pointer. (correct me if I'm wrong.) But the address of function is different from one run to another.
So, the question - is there any way to create list of functors that will be relevant all the time?
I'd recommend some kind of paired data structure with an identifier on one side and the function pointer on the other. If there are enough of them something like a map:
typedef void (*fptr_t)(); // or whatever your function pointer type is
std::map<std::string, fptr_t> fptr_map;
Your application should build this map when it is first needed and cache the result. Then when you "write" the function pointers to a file, you should write the unique std::string keys instead. When the application "reads" the function pointers it will read in the keys and map them to the function pointers for that invocation of the program.
One possible solution, as #fbrereto mentions, is to label different functors with some unique identifier (integer, string, uuid, etc.), that does not depend on addresses in each particular process, and store these keys into the file. Then you can use something the Factory Design Pattern to instantiate functors on demand when reading the file.
Yes, function pointer is just an address. You can't rely on it. Instead you can create array of functors and store indexes of functors to file. or you can create hashtable and reference functors by name.