Searching a set of unique pointers - c++

I have a set of unique pointers pointing to objects. Occasionally, I will reveal some of the raw pointers to these objects so other parts of the code can do stuff with the objects. This code does not know whether the pointers are pointing to objects maintained by a certain set of unique pointers or not, so I need to check whether the object pointed to by a pointer is in a unique pointer set.
In simple code:
int* x = new int(42);
std::set<std::unique_ptr<int>> numbers;
numbers.insert(std::unique_ptr<int>(x));
numbers.find(x) // does not compile
I understand why the code does not compile, but I cannot think of a way to search for the element with the STL. Is there anything that caters to my needs or will I have to iterate over all elements of the set manually?

You can use std::find_if like this:
std::find_if(numbers.begin(), numbers.end(), [&](std::unique_ptr<int>& p) { return p.get() == x;});

Why not use boost::ptr_set instead?

Related

Reason for using smart pointers with a container

Simply written I would like to ask "what is a good reason to use smart pointers?"
for ex std::unique_ptr
However, I am not asking for reasons to use smart pointers over regular (dumb) pointers. I think every body knows that or a quick search can find the reason.
What I am asking is a comparison of these two cases:
Given a class (or a struct) named MyObject use
std:queue<std::unique_ptr<MyObject>>queue;
rather than
std:queue<MyObject> queue;
(it can be any container, not necessarily a queue)
Why should someone use option 1 rather than 2?
That is actually a good question.
There are a few reasons I can think of:
Polymorphism works only with references and pointers, not with value types. So if you want to hold derived objects in a container you can't have std::queue<MyObject>. One options is unique_ptr, another is reference_wrapper
the contained objects are referenced (*) from outside of the container. Depending on the container, the elements it holds can move, invalidating previous references to it. For instance std::vector::insert or the move of the container itself. In this case std::unique_ptr<MyObject> assures that the reference is valid, regardless of what the container does with it (ofc, as long as the unique_ptr is alive).
In the following example in Objects you can add a bunch of objects in a queue. However two of those objects can be special and you can access those two at any time.
struct MyObject { MyObject(int); };
struct Objects
{
std::queue<std::unique_ptr<MyObject>> all_objects_;
MyObject* special_object_ = nullptr;
MyObject* secondary_special_object_ = nullptr;
void AddObject(int i)
{
all_objects_.emplace(std::make_unique<MyObject>(i));
}
void AddSpecialObject(int i)
{
auto& emplaced = all_objects_.emplace(std::make_unique<MyObject>(i));
special_object_ = emplaced.get();
}
void AddSecondarySpecialObject(int i)
{
auto& emplaced = all_objects_.emplace(std::make_unique<MyObject>(i));
secondary_special_object_ = emplaced.get();
}
};
(*) I use "reference" here with its english meaning, not the C++ type. Any way to refer to an object (e.g. via a raw pointer)
Usecase: You want to store something in a std::vector with constant indices, while at the same time being able to remove objects from that vector.
If you use pointers, you can delete a pointed to object and set vector[i] = nullptr, (and also check for it later) which is something you cannot do when storing objects themselves. If you'd store Objects you would have to keep the instance in the vector and use a flag bool valid or something, because if you'd delete an object from a vector all indices after that object's index change by -1.
Note: As mentioned in a comment to this answer, the same can be archieved using std::optional, if you have access to C++17 or later.
The first declaration generates a container with pointer elements and the second one generates pure objects.
Here are some benefits of using pointers over objects:
They allow you to create dynamically sized data structures.
They allow you to manipulate memory directly (such as when packing or
unpacking data from hardware devices.)
They allow object references(function or data objects)
They allow you to manipulate an object(through an API) without needing to know the details of the object(other than the API.)
(raw) pointers are usually well matched to CPU registers, which makes dereferencing a value via a pointer efficient. (C++ “smart” pointers are more complicated data objects.)
Also, polymorphism is considered as one of the important features of Object-Oriented Programming.
In C++ polymorphism is mainly divided into two types:
Compile-time Polymorphism
This type of polymorphism is achieved by function overloading or operator overloading.
Runtime Polymorphism
This type of polymorphism is achieved by Function Overriding which if we want to use the base class to use these functions, it is necessary to use pointers instead of objects.

How to use multiple pointers to an object by vector/map

I have a question about using multiple pointers to an object.
I have a pointer in a vector and another one in a map.
The map uses the vector to index the object. Example code:
class Thing
{
public:
int x = 1;
};
Thing obj_Thing;
std::vector<Thing*> v_Things;
v_Things.push_back(&obj_Thing);
std::map<int, Thing*> m_ThingMap;
m_ThingsMap[v_Things[0]->x] = v_Things[0]; // crucial part
is it good practice to assign pointers to each other like this?
Should the vector and/or map hold addresses instead? Or should I be using a pointer to pointer for the map?
It all depends on what you want to do.
However, your approach can get really hairy when your project grows, and especially when others contribute to it.
To start with, this:
m_ThingsMap[v_Things[0]->x] = v_Things(0);
should be:
m_ThingsMap[v_Things[0]->x] = v_Things[0];
Moreover, storing raw pointers in a std::vector is possible, but needs special care, since you may end up with dangling pointers, if the object that a pointer points to gets deallocated too soon.
For that I suggest you to use std::weak_ptr, like this:
std::vector<std::weak_ptr<Thing>> v_Things;
in case you decide to stick with that approach (I mean if the pointer points to an object that is pointer-shared from another pointer).
If I were you, I would redesign my approach, since your code is not clean enough, let alone your logic; it takes one moment or two for someone to understand what is going on with all the pointers and shared places.

Hook on object in std::list. Pointer or iterator?

I looked for the same type of question but I didn't find the answer to my question (existential one):
What type of hook should I choose to keep control over an object in a list?
I waver between pointer and iterator.
The container is filled at the beginning and shouldn't be resized after that. The hook is the way I use to switch between my objects at the whim of user and manipulating only one variable in my algorithm.
In all cases, I must go through an iterator to find the right object to hook. But which one is the best practice/use?
// 10 object list
std::list <Object> List(10);
std::list <Object>::iterator it = List.begin();
Object *pt = NULL;
// Select the 3rd object
advance(it, 3);
pt = &(*it);
// Access to object member...
it->member;
pt->member;
Pointers allow not to access to neighbours, contrary to iterators, but may be unsafe.
What's the best pratice?
It depends on what you want to do with the "hook". If you use
an iterator, it can be used as the starting point for moving
forward or backward in the list. If you use a pointer, you can
also point to objects outside of the list. In the end, it
depends on how you expect your code to evolve.
Storing pointers or iterators into a container is quite risky because you might find they're invalid by the time you use them (i.e. if the container or the data changes).
A more generalised and robust approach might be to use a map instead of a list. Every value is identified by a key (of whatever type you like), and you can easily store the keys and check whether or not they're valid before you use them, e.g.:
std::map<int, std::string> data;
// Add stuff to the map
data[5] = "blah";
data[27] = "foo";
// Check if a key exists
if (data.find(31) == data.end()) {
// Key 31 does NOT exist
} else {
// Key 31 DOES exist
}
One thing to be aware of though is that maps are ordered by key value. That means if the sequence of elements is important then you'll need to choose your keys carefully.
In most cases use references:
Object& ref = *it;
ref.member
It behaves like a pointer (so feel free to pass it around functions) but you can't do pointer arithmetics on it (ref++ will actually call the operator++() on Object). Also you can't initialize it from null (will be reported as an error when you try to create the reference).
One thing to remember you still need the object to be alocated somewhere. If say some function deletes the Object from List you shouldn't use ref anymore.

C++ Safe returning a pointer to an iterater after map insert?

So I have some C++ classes that use a map and key class for a sort of data structure. In my insert method I use the typical map.insert. I want this function to return a pointer so I can modify some values (not the one used for comparison) inside the element inserted. So I was wondering if this is safe to this..
template<typename T>
NodeT<T> * TreeT<T>::
MakeNode(PointT point)
{
NodeT<T> * prNode = new NodeT<T>;
//set the contents for the node
prNode->SetNode(point, m_dTolerance);
//Create the key class using the
VectorKey key(point, m_dTolerance);
//Store the key,node as a pair for easy access
return_val = m_tree.insert( pair<VectorKey, NodeT<T> >(key, *prNode) );
if (return_val.second == false)
//if return_val.second is false it wasnt inserted
prNode = NULL;
else
//it was inserted, get a pointer to node
prNode = &(return_val.first->second); //is this safe if I plan to use it later?
return prNode;
}
I seemed to learn the hard way that my original pointer (the one I created with new), was pointing to the wrong element after the insert. Can anyone tell me why that is? So I used the return_val iterator to get the right pointer. I kinda dont want to return an iterator but if its safer then I do...
Thanks!
You seems to have troubles in your code with pointers and values. First you allocate an object on a heap ( with new Node )
Then you use a copy of that object to sore within your map.
PS. And then you loose original object forever as do not free memory which leads to memory leak.
In your case - it is invalid because you return pointer to object which can be deleted at any time ( for example next time you add something to your map and map decides to reallocate it's tree, so it will copy objects to different places ).
Storing pointers as map values prevents this. The only thing you need to remember to clear them up when removing object from map and when removing map itself.
The easy way to handle that would be using smart pointers (boost::shared_ptr for example ) or smart map class (boost::ptr_map for example ).
To fix that - use pointers everywhere ( store a pointer as a map value ).
This way - you will be able to return pointer from this function and it will be valid.
So just turn your map to map*> and this should fix most of your problems.
Do not forger to delete objects when erasing them from the map.
This code sample is interesting because contains a several things wrongs or to avoid.
Implementation
The most important things are been said (mainly by Bogolt):
You are leaking memory, because allocate NodeT<T> from the heap and never free it again, since map will allocate a copy of the object, not the pointer. Indeed, you specify as parameter *prNode, not prNode.
You use the heap to allocate the object (will be copied into the map), but you assume you always allocate the object. Despite it will be the very most probably case, that is not alway true: new operator would be return null or throw a bad_alloc exception. The code does not handle it.
Anyway, you use the heap when is not really needed. (And you see the problems are you intriducing because that). You can just create the object in the stack and then insert into the map, avoiding the previous problems and typing less code.
Design
The function returns a pointer to the element in the map. Depending the program, is possible this is safe. But what happens if the code reference the pointer when the object is removed from the map? Better, if you are returning pointer, do not return a raw pointer. Use smart pointer (shared_ptr in this case) instead. Using shared_ptr you will have not problems with the object life.
Other reason to use smart pointers: because the insertion into the map imply a copy of the element, you are imposing a requirement to NodeT<T>: it has to be copy constructible. May be this requirement is not important for performance, but may be in other circumstances copying the object have drawbacks. If you use smart pointer (or boost::ptr_map), the object will be created just once and is not copied.
Style
Just some suggestion, but not too important:
instead type pair<VectorKey, NodeT<T> >(key, *prNode), type make_pair(key, *prNode). The code is more compact and clearer typing less.
Well I'd say that depends on is your map alive longer than anything that could use (and store) the pointer.
If yes, (ie, it's in some sort of singleton), you could go with it, but not very safe anyway since any code could delete the pointer.
The best option is to store boost::shared_ptr (or std:: since c++11) instead of raw pointers in your mapn and return only a weak_ptr after insertion.
That way, you're sure no other code can delete your pointer as long as the map holds it, and that no one can use a pointer that has been erased from the map.

Is this the right way to delete and erase pointers to objects stored in a vector?

I am not very good with STL and I saw few post similar to my requirement and got confused. So, I need some suggestion on following code.
SomeStruct someStruct(identifier);
std::vector<SomeStruct*>::iterator it = std::find_if(vWrapper.begin(), vWrapper.end(), SomeStruct::Find_SomeStruct(&someStruct));
if(it != vWrapper.end())
{
...
delete *it;
it = vWrapper.erase(it);
}
I am trying to peek into vector based on identifier and then delete pointer to object stored in vector.
I saw the post. It makes use of for loop and reassigns the iterators. Also, none of the post has used find_if() then delete and erase.
Am I doing it the right way?
Formally, what you're doing is undefined behavior, but practically
speaking, it's fine. The undefined behavior occurs because
std::vector requires that all of its contents be copiable and
assignable, at all times, and delete makes the pointer value it was
passed invalid, and thus uncopiable. In practice: std::vector isn't
going to copy the pointer value if you erase it immediately after, and I
don't know of a machine today where a deleted pointer value can't really
be copied without risk. (Just don't dereference it.) If you really
want to avoid the undefined behavior, you can do something like:
SomeStruct* tmp = *it;
it = vWrapper.erase(it);
delete tmp;
but frankly, I'm not sure it's worth the effort.
That invokes undefined behavior. For explanation, read #James Kanze's answer.
I would rather move to next question: if in the other topic, none of the answer have used std::find_if, then it is because those posts do not talk about deleting and erasing a particular element. They
seem to delete all the elements, or few of them have used functor where they check which objects to delete, which is also fine.
But the major difference between your code, and their code is that your code deletes and erases at most one object, and their code could delete all objects (the one which uses functor and inside the functor it deletes the object on meeting the condition).
Well this is what I could say for a correctly written std::find_if.
However, in reality, I couldn't understand your code, especially these two lines:
//I formatted the code so that entire code is visible without
//scrolling horizontally
SomeStruct someStruct(identifier);
std::vector<SomeStruct*>::iterator it = std::find_if
(
vWrapper.begin(),
vWrapper.end(),
SomeStruct::Find_SomeStruct(&identifier)
);
What is the first line doing there? You declared a variable and forgot it? Well maybe, you use it somewhere else; in that case, it is okay.
But what is SomeStruct::Find_SomeStruct? Is it a nested class which can act like a functor? a static function or what? Does your compile successfully? A complete answer also depends on these questions which I posed.
Personally, I do not have raw pointers in a container, not to deal with problems that you ask. I do not think to choose the right way to delete them. Use a smart pointer, like std::shared_ptr, instead, and it will delete its raw pointer it owns, when the smart pointer goes out of the scope by RAII.
So instead of
std::vector<SomeStruct*> vec;
, use
std::vector<std::shared_ptr<SomeStruct>> vec;
So how about deleting an item?
vec.erase(std::remove_if( vec.begin(), vec.end(),
[&vec]( std::shared_ptr<SomeStruct> & item )
{
bool condition = // The condition on which the item will de deleted. e.g. item->x == 0;
return condition;
}
),vec.end());