So I'm writing an API in C++ to be used in another GUI application I'll be writing. The API will allow the user to create instances of "MyObject" and modify the properties of that object, but the object itself will not be exposed to the client, only an ID to that object. So for instance:
Object_ID identifier = myApiCreateObject();
myApiModifyProperty(identifier, "PROPERTY_NAME", "value");
So the identifier acts as an external handler to a specific MyObject instance.
As of right now the Object_ID is defined as follows:
typedef int Object_ID;
Currently all MyObject instances are stored in an std::vector within my API. The Object_ID is simply the index in the vector that the desired instance lives.
The problem with this approach is that I don't know how to handle deleting instances of MyObject from the vector. For instance, let's say I have 10 instances of MyObject created and I want to delete the instance at index 5, I would want to do something like the following:
myApiDeleteObject(handlerForIndex5);
By doing this though, internally my API would remove that object from the std::vector and then would have to shift over all the objects at indices > 5. This would cause my external handlers to no longer reference the correct object.
So just using the index of the array by itself is not sufficient, but I don't know of a better alternative without having to expose the MyObject class to the client.
EDIT
Here's an updated example highlighting the issue at hand:
Internally the API performs certain algorithms on the list of objects, some of these algorithms require sorting the vector as a step.
So my GUI would do something like :
myApiBeginCalculations();
and then internally the API would be doing something like this:
myApiBeginCalculations()
{
//Start algorithm
.......
Sort(vector);
//Continue with algorithm
}
Then let's say after that algorithm is complete, the user wants to modify a given MyObject instance and start again:
myApiBeginCalculations();
myApiModifyProperty(myHandler, "PROPERTY", "VALUE");
myApiBeginCalculations();
myApiDeleteObject(myHandler);
myAPiBeginCalculations();
Internally myApi will be doing a bunch of things to the MyObject instances and I need a reliable way to keep track of individual instances on the client even as they get shuffled around.
You can use std::map in place of std::vector. So you can do look up quickly and remove objects whenever you need.
std::map<int, Object> Object_directory
You need to use an ID based on something that is both unique for each object and which remains constant for each object. Clearly an index into a vector you're continually rearranging does not qualify.
You haven't described the properties of the objects so I can't say whether there's something already suitable for this use, but if not then you can add something. You can assign an IDs to each object as you create them, or you could allocate the objects on the heap so that their addresses remain consistent as you, for example, sort a vector<unique_ptr<MyObject>>.
You'll have to consider each operation you need to perform and figure out the necessary performance. For example a linear search through the vector in order to find an object with a matching ID may be too slow for some purpose. In that case you'll have to figure out how to avoid that linear search, perhaps by keeping a map on the side or something, at the cost of having to keep the map updated during other operations.
I would suggest not generating an ID number at all. Simply use a real pointer to the actual Object instance instead. To hide it from the client, you can use void* or uintptr_t, and just have your API functions type-cast that value to an Object* pointer when needed. You can still keep track of the Object instances in a std::vector so you can perform your algorithms on the objects, but the order of the std:vector will not be important to clients, and deleting any given Object will not invalidate other object IDs.
typedef uintptr_t Object_ID;
typedef std::vector<Object*> ObjectVector;
typedef ObjectVector::iterator ObjectVectorIter;
ObjectVector objVec;
Object_ID myApiCreateObject()
{
try
{
std::auto_ptr<Object> obj(new Object);
objVec.push_back(obj.get());
return reinterpret_cast<Object_ID>(obj.release());
}
catch (const std::exception&)
{
return 0;
}
}
ObjectVectorIter myApiFindObject(Object_ID identifier)
{
Object *obj = reinterpret_cast<Object*>(identifier);
return std::find(objVec.begin(), objVec.end(), obj);
}
void myApiModifyProperty(Object_ID identifier, const char* propName, const char* propValue)
{
ObjectVectorIter iter = myApiFindObject(identifier);
if (iter != objVec.end())
iter->property[propName] = propValue;
}
void myApiDeleteObject(Object_ID identifier)
{
ObjectVectorIter iter = myApiFindObject(identifer);
if (iter != objVec.end())
{
Object* obj = *iter;
objVec.erase(iter);
delete obj;
}
}
Or, if you are using C++11:
typedef uintptr_t Object_ID;
typedef std::shared_ptr<Object> ObjectPtr;
typedef std::vector<ObjectPtr> ObjectVector;
typedef ObjectVector::iterator ObjectVectorIter;
ObjectVector objVec;
Object_ID myApiCreateObject()
{
try
{
ObjectPtr obj = std::make_shared<Object>();
objVec.push_back(obj);
return reinterpret_cast<Object_ID>(obj.get());
}
catch (const std::exception&)
{
return 0;
}
}
ObjectVectorIter myApiFindObject(Object_ID identifier)
{
Object *obj = reinterpret_cast<Object*>(identifier);
return std::find_if(objVec.begin(), objVec.end(), [obj](const ObjectPtr &p){ return p.get() == obj; });
}
void myApiModifyProperty(Object_ID identifier, const char* propName, const char* propValue)
{
ObjectVectorIter iter = myApiFindObject(identifier);
if (iter != objVec.end())
(*iter)->property[propName] = propValue;
}
void myApiDeleteObject(Object_ID identifier)
{
ObjectVectorIter iter = myApiFindObject(identifier);
if (iter != vec.end())
objVec.erase(iter);
}
Related
In my program, I have classes I use for handling projectiles in a game.
class Projectile
{
bool IsActive;
bool GetActive();
//....
};
class Game
{
std::vector<Projectile*> ProjectilesToUpdate;
//....
};
Of course, there is more to it than that, however I'm trying to stay relevant to my current problem.
I want to use std::sort to make it so that all projectiles where IsActive == true are at the far beginning and that any projectile which isn't active is at the very end.
How would I go about doing this?
Basically, you want to create a partition:
std::partition(std::begin(ProjectilesToUpdate),
std::end(ProjectilesToUpdate),
[](Projectile const* p) { return p->GetActive(); }
);
As for the subsidiary questions:
I had to remove the "const" part in the code to make it compile.
That's because your GetActive() method should be const:
bool GetActive() const { return IsActive; }
See Meaning of "const" last in a C++ method declaration?
how can I use this to delete every single object (and pointer to object) that is no longer needed?
You could use smart pointers (such as std::shared_ptr) and no longer care about delete. Thus you could use the Erase–remove idiom as follow:
std::vector<std::shared_ptr<Projectile>> ProjectilesToUpdate;
// :
// :
auto it = std::remove_if(
std::begin(ProjectilesToUpdate),
std::end(ProjectilesToUpdate),
[](std::shared_ptr<Projectile> const& p) { return !p->GetActive(); } // mind the negation
);
ProjectilesToUpdate.erase(it, std::end(ProjectilesToUpdate));
Related question: What is a smart pointer and when should I use one?
If you don't want to use smart pointers, you could use the returned iterator which point to the first element of the second group (i.e. the non active ones) and iterate until the end of the array:
auto begin = std::begin(ProjectilesToUpdate);
auto end = std::end(ProjectilesToUpdate);
auto start = std::partition(begin, end,
[](Projectile const* p) { return p->GetActive(); }
);
for (auto it = start; it != end; ++it) {
delete *it;
}
ProjectilesToUpdate.erase(start, end);
Note that I'm not calling erase inside the loop since it invalidates iterators.
And of course, this last solution is more complex than using smart pointers.
I have the following classes in a program.
class Class1 {
public:
boost::ptr_vector<Class2> fields;
}
class Class2 {
public:
std:string name;
unsigned int value;
}
I want to write a member function in Class1 that returns a reference or pointer to an element in fields based on Class2's name variable. I don't have to be concerned with the lifetime of the objects in the container.
Currently, I am returning an iterator to the element I want after the function searches from the start of the vector to the element.
boost::ptr_vector<Class2>::iterator getFieldByName(std::string name) {
boost::ptr_vector<Class2>::iterator field = fields.begin();
while (field != fields.end()) {
if (field->name.compare(name) == 0) {
return field;
}
++field;
}
return fields.end();
}
The problems that I'm facing are:
(1.) I need to have fast random access to the elements or the program sits in getFieldByName() too long (a boost::ptr_vector<> is too slow when starting at the beginning of the container)
(2.) I need to preserve the order of insertion of the fields (so I can't use a boost::ptr_map<> directly)
I have discovered Boost::MultiIndex and it seems like it could provide a solution to the problems, but I need to use a smart container so that destruction of the container will also destruct the objects owned by the container.
Is there anyway to achieve a smart container that has multiple methods of access?
You can use two containers. Have a boost::ptr_map<> that stores the actual data, and then have a std::vector<> that stores pointers to the nodes of the map.
boost::ptr_map<std::string, Class2> by_field;
std::vector<Class2 const*> by_order;
void insert(Class2* obj) {
if (by_field.insert(obj->name, obj).second) {
// on insertion success, also add to by_order
by_order.push_back(obj);
}
}
This will give you O(lg n) access in your getFieldByName() function (just look it up in by_field) while also preserving the order of insertion (just look it up in by_order).
I am implementing a distributed map in c++ and searching for a good API design.
First and straightforward option is to make it exactly like std::map. Problem is with iterator.
IMap<std::string,Person>::iterator it;
it = map.find("sample");
if(it == map.end() ){
//NULL
}
for(it = map.begin(); it != map.end(); it++){
//iterate
}
In distributed context(at least in the one i am implementing) , there is no begin and end of the map. It is not ordered in anyway, so returning an iterator does not look like an option.
Second option is returning the value class by copy like below:
Person emptyPerson;
Person person = map.get("sample");
if(person == emptyPerson){
//NULL
}
Problem is with that NULL check looks strange. You can first ask if it is available and then get the object, but the requirement is that these operations must be atomic.
Third option is returning pointer:
Person* person = map.get("sample");
if(person == NULL){
//NULL
}
I don't want to do it this way, because it is error prone. User needs to delete the pointer that i created internally.
I am thinking about returning a class that wrapping user object like:
value_reference<std::map, Person> person = map.get("sample");
if(value_reference.hasValue() ){
Person p = value_reference;
}
So what do you think the best approach is?
Do you know any good api similar to requirements my distributed map?
Based on your term "distributed map" I am making the following assumptions:
A subset of the data is available locally, and for the set of data that is not some remote-fetch will need to be performed.
Writes to the returned object should not be automatically persisted in the data store. An explicit update request should be made instead.
If this is true then iterators are not what you want, nor do you want the STL container model. The C++ Iterator concept requires you to implement the pre-increment (++i) operator, and if your data is unordered and spread across multiple nodes, then the request "give me the next entry" does not make sense.
You could create a terrible kludge if you wanted to simulate STL containers and iterators for interoperability reasons: have the map's end() method return a sentinel iterator instance, and have operator++() for your iterators return this same sentinel. Effectively, every iterator would point to "the last element in the map." I would strongly advise against taking this approach unless it becomes necessary, and I don't think it will be.
It sounds like what you want is a simple CRUD model, where updates must be explicitly requested. In that case, your API would look something like:
template <typename TKey, typename TValue>
class IMap<TKey, TValue>
{
public:
void create(TKey const & key, TValue const & value) = 0;
std::unique_ptr<TValue> retrieve(TKey const & key) = 0;
bool update(TKey const & key, TValue const & value) = 0;
bool remove(TKey const & key) = 0;
};
In the retrieve case, you would simply return a null pointer as you suggested. std::unique_ptr<> will ensure that the caller will either delete the allocated object or explicitly take ownership of it.
An alternative to the "return pointer to newly-allocated object" case would be to let the caller pass in a reference, and the method would return true if the value was found in the map. This will, for example, let the caller retrieve an object directly into an array slot or other local structure without the need for an intermediary heap allocation.
bool retrieve(TKey const & key, TValue & value) = 0;
Use of this method would look something like:
Person person;
if (map.retrieve("sample", person)) {
std::cout << "Found person: " << person << std::endl;
} else {
std::cout << "Did not find person." << std::endl;
}
You could provide both overloads too, and the one returning a pointer can be implemented in terms of the other by default:
template <typename TKey, typename TValue>
std::unique_ptr<TValue> IMap<TKey, TValue>::retrieve(TKey const & key)
{
TValue v;
return std::unique_ptr<TValue>(retrieve(key, v) ? new TValue(v) : nullptr);
}
I'd say something like option 3 is best. You could just emulate it using one of the standard smart pointer types introduced in C++11, so you still create a pointer, but the user doesn't have to free it. So something like:
std::unqiue_ptr<Person> person = map.get("sample");
if(person) {
person->makeMeASandwitch();
}
I have spent some time looking for answers but didn't find anything that was satisfactory.
Just interested in how some more seasoned C++ people solve this kind of problem as now I am doing a little more production related coding than prototyping.
Let say you have a class that has say a unordered_map (hashmap) that holds a lot of data, say 500Mb. You want to write an accessor that returns some subset of that data in an efficient manner.
Take the following, where BigData is some class that stores a moderate amount of data.
Class A
{
private:
unordered_map<string, BigData> m_map; // lots of data
public:
vector<BigData> get10BestItems()
{
vector<BigData> results;
for ( ........ // iterate over m_map and add 10 best items to results
// ...
return results;
}
};
The accessor get10BestItems is not very efficient in this code because it first copies the items to the results vector, then the results vector is copied when the function is returned (copying from the function stack).
You can't have a vector of references in c__ for various reasons, which would be the obvious answer:
vector<BigData&> results; // vector can't contain references.
You could create the results vector on the heap and pass a reference to that:
vector<BigData>& get10BestItems() // returns a reference to the vector
{
vector<BigData> results = new vector<BigData>; // generate on heap
for ( ........ // iterate over m_map and add 10 best items to results
// ...
return results; // can return the reference
}
But then you are going to run into memory leak issues if you are not careful. It is also slow (heap memory) and still copies data from the map to the vector.
So we can look back at c-style coding and just use pointers:
vector<BigData*> get10BestItems() // returns a vector of pointers
{
vector<BigData*> results ; // vectors of pointers
for ( ........ // iterate over m_map and add 10 best items to results
// ...
return results;
}
But most sources say to not use pointers unless absolutely necessary. There are options to use smart_pointers and the boost ptr_vector but I rather try to avoid these if possible.
I do no that the map is going to be static so I am not too worried about bad pointers. Just one issue if the code will have to be difference to handle pointers. Stylistically this is not pleasant:
const BigData& getTheBestItem() // returns a const reference
{
string bestID;
for ( ........ // iterate over m_map, find bestID
// ...
return m_map[bestID] ; // return a referencr to the best item
}
vector<BigData*> get10BestItems() // returns a vector of pointers
{
vector<BigData*> results ; // vectors of pointers
for_each ........ // iterate over m_map and add 10 best items to results
// ...
return results;
};
E.g., if you want a single item then it is easy to return a reference.
Finally option is to simply make the Hash-map public and return a vector of keys (in this case strings):
Class A
{
public:
unordered_map<string, BigData> m_map; // lots of data
vector<string> get10BestItemKeys()
{
vector<string> results;
for (........ // iterate over m_map and add 10 best KEYS to results
// ...
return results;
}
};
A aTest;
... // load data to map
vector <string> best10 = aTest.get10BestItemKeys();
for ( .... // iterate over all KEYs in best10
{
aTest.m_map.find(KEY); // do something with item.
// ...
}
What is the best solution? Speed is important but I want ease of development and safe programming practices.
I would just go with a vector of pointers if the map is constant. You can always return const pointers if you want to avoid the data being changed.
References are great for when they work but there's a reason we still have pointers (for me this would fall under the category of being 'necessary').
I would do something similar to the following:
Class A
{
private:
unordered_map<string, BigData> m_map; // lots of data
vector<BigData*> best10;
public:
A()
: best10(10)
{
// Other constructor stuff
}
const vector<BigData*>& get10BestItems()
{
// Set best10[0] through best10[9] with the pointers to the best 10
return best10;
}
};
Note a few things:
The vector isn't being reallocated each time and is being returned as a constant reference, so nothing is allocated or copied when you call get10BestItems.
Pointers are just fine in this situation. The things you read about avoiding pointers were probably in relation to heap allocations, in which case std::unique_ptr or std::shared_ptr are now preferred.
This sounds like a job for boost::ref to me. Just change your original code slightly:
typedef std::vector<boost::ref<BigData> > BestItems;
BestItems get10BestItems()
{
BestItems results;
for ( ........ // iterate over m_map and add 10 best items to results
// ...
return results;
}
Now you're notionally only returning a reference to each item within your return vector making it small and cheap to copy (if the compiler isn't able to optimize away the return copy completely).
I usually use boost::range and I found it is invaluable in so many situations, especially the one you describe.
You can keep the range object and iterate over it, etc.
But I should mention I don't know what happens if you add/remove on object between when you get the range and when you use it, so you may want to check that out before using it.
I have a function that translates data using std::map
struct HistoParameter
{
int nbins;
float first;
float last;
HistoParameter(int _nbins, int _first, int _last) :
nbins(_nbins), first(_first), last(_last) {};
};
HistoParameter* variable_to_parameter(char* var_name)
{
std::map<const std::string, HistoParameter*> hp;
hp[std::string("ph_pt")] = new HistoParameter(100,0,22000);
hp[std::string("ph_eta")] = new HistoParameter(100,-3,3);
// ...
return hp[var_name];
}
My struct is very light, but image it can be heavy. The prolem is that every time I call this function it create a lot of HistoParameter objects, maybe a switch case is more efficient. First question: I'm creating garbage?
Second solution:
bool first_time = true;
HistoParameter* variable_to_parameter(char* var_name)
{
static std::map<const std::string, HistoParameter*> hp;
if (first_time)
{
hp[std::string("ph_pt")] = new HistoParameter(100,0,22000);
hp[std::string("ph_eta")] = new HistoParameter(100,-3,3);
// ...
}
first_time = false;
return hp[var_name];
is it ok? Better solution?
The second solution seems OK to me - you can say:
if ( hp.empty() ) {
// populate map
}
I would also consider making it a map of values rather than pointers - I don't see you need dynamic allocation here:
std::map <std::string, HistoParameter> hp;
then:
hp["ph_pt"] = HistoParameter(100,0,22000);
Note you don't need the explicit std::string conversion. Or better still:
hp.insert( std::make_pair( "ph_pt", HistoParameter(100,0,22000 )));
The first solution produces a lot of garbage. Why don't you return the class by value? It's quite lightweight, and you wouln't have to dynamically allocate it.
HistoParameter variable_to_parameter(char* var_name)
{
static std::map<const std::string, HistoParameter> hp;
if ( hp.empty() )
{
hp.insert( std::make_pair( "ph_pt", HistoParameter(100,0,22000) ) );
hp.insert( std::make_pair( "ph_eta", HistoParameter(100,-3,3) ) );
//...
}
return hp[var_name];
}
If the class returned gets larger, and you want a power-tool, then try out boost::flyweight.
If you don't want to pass back a big structure, you can do:
HistoParameter& variable_to_parameter(char* var_name)
{
// same code
}
... and even throw in a const if you want it immutable.
Edit: added make_pair, as suggested by Niel.
Your second solution should certainly improve efficiency, but isn't (at least IMO) the best implementation possible. First of all, it makes first_time publicly visible, even though only variable_to_parameter actually cares about it. You've already made hp a static variable in the function, and first_time should be as well.
Second, I would not use pointers and/or dynamic allocation for the HistoParameter values. At one int and two floats, there's simply no reason to do so. If you're really passing them around so much that copying became a problem, you'd probably be better off using some sort of smart pointer class instead of a raw pointer -- the latter is more difficult to use and much more difficult to make exception safe.
Third, I'd consider whether it's worthwhile to make variable_to_parameter into a functor instead of a function. In this case, you'd initialize the map in the ctor, so you wouldn't have to check whether it was initialized every time operator() was invoked. You can also combine the two, by have a static map in the functor. The ctor initializes it if it doesn't exist, and operator() just does a lookup.
Finally, I'd note that map::operator[] is primarily useful for inserting items -- it creates an item with the specified key if it doesn't exist, but when you're looking for an item, you usually don't want to create an item. For this, you're generally better off using map.find() instead.
I'd have a std::map< std::string, HistoParameter *> member and do
InitializeHistoParameter()
{
myMap["ph_pt"] = new ...
myMap["ph_eta"] = new ...
}
And then
HistoParameter* variable_to_parameter(char* var_name)
{
return myMap[var_name];
}
either way, you are creating memory leak.
each time the = operator is called, for example:
hp[std::string("ph_pt")] = new HistoParameter(100,0,22000);
you are creating a new HistoParameter object and pairing the key "ph" with this most recent object, leaving the previous one dangling.
If creating a new object each time is your actual intent, you probably need to call
delete hp[std::string("ph_pt")];
before the new operation.
My suggestion is to avoid raw new operations as much as possible and resort to smart pointers such as boost::share_ptr for object life time management.