Using boost::shared_ptr to refer to iterator without copying data? - c++

Inside a loop I need to call a function which has an argument of type pcl::PointIndicesPtr. This is actually a boost::shared_ptr< ::pcl::PointIndices>. Is there a way to do this without having to copy the underlying data? I only could it get to work by using make_shared, which copies the object if I understand it correctly.
for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
{
pcl::PointIndicesPtr indices_ptr2 =boost::make_shared<pcl::PointIndices>(*it);
}
For example this will crash at runtime:
for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin (); it != cluster_indices.end (); ++it)
{
pcl::PointIndices test = *it;
pcl::PointIndicesPtr indices_ptr3(&test);
}

The answer depends on the implementation of the function you are calling and what else your code does with the object. There is no "one right answer".
For example, if the function can't possibly access the object after it returns, the right answer might be to wrap the existing object with a shared_ptr with a dummy destructor. But if the function stashes the shared_ptr, that won't work.
If your own code never modifies the object, constructing the object with make_shared in the first place may be the right answer. But if your code modifies the object while the function expects it not to change later, that won't work.
You have to make a decision based on all the information.
The most important question to answer -- why does the function you are calling take a shared_ptr? Does it have a good reason? If so, what is that reason? If not, why not change it to take a reference?

Could you use BOOST_FOREACH?
i.e.
BOOST_FOREACH(pcl::PointIndiciesPtr ptr; cluster_indicies)
{
//do something with shared_ptr
}

Related

Can the [this] pointer captured by a lambda be invalidated before the lambda runs?

Suppose that we have a STL container with some objects, and these objects can post functions to a queue to be executed later. But before these functions get executed, the container gets modified in such a way that pointers pointing to that object are invalidated. Let me illustrate with an example:
#include <vector>
#include <functional>
class Class_A
{
public:
std::function<void()> getFunctionToRunLater()
{
return [this] () { somethingToDo(); moreThingsToDo(); };
// Returns a lambda function that captures the this pointer,
// so it can access the object's methods and variables.
}
void somethingToDo();
void moreThingsToDo();
}
int main()
{
std::vector<Class_A> vec;
vec.push_back(Class_A());
std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();
// More code...
pendingFunction();
}
Everything fine, right? We get a function the object wants to run and, after some logic, we execute that function. This represents posting functions to a queue and them execute all functions in the queue. But now look at this one:
int main()
{
std::vector<Class_A> vec;
vec.push_back(Class_A());
std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();
// More code...
vec.reserve(1000);
// This will surely reallocate the vector, invalidating all pointers.
pendingFunction();
// And now my program is going straight down to hell, right?
}
Is my assumption correct? What will happen if the lambda doesn't capture anything at all, will the program still be logically broken? And what about if the lambda doesn't capture the this pointer, but rather some other class field specifically?
The existing answer already mentions that the pointer can be invalidated. One way to avoid the problem is, as already mentioned, changing the ownership of *this by either shared_ptr, unique_ptr or a copy. However, this comes at extra cost (dynamic allocation or extra copy) and sometimes is simply not possible (non-copyable types).
Instead, I would suggest a design that doesn't lead to this problem in the first place, i.e. not making the this pointer part of the lambda's state. Take the object as a parameter:
std::function<void(Class_A&)> getFunctionToRunLater()
{
return [] (Class_A& obj) { obj.somethingToDo(); obj.moreThingsToDo(); };
}
If copying the object is a possibility, then you can capture *this by value: (requires C++17)
return [*this] { somethingToDo(); moreThingsToDo(); }
This copies the whole object into the closure to avoid out-of-lifetime access to the original object.
Yes this program is likely to have problems. C++ does not protect you from invalidating pointers, and as you've highlighted the objects in your vector will potentially move address when the vector resizes, which will cause problems if you try to run your lambda.
You will probably be unable to compile the program without capturing this. You will also end up with issues if you try to capture references or pointers to any part of your object without being sure the memory being pointed at will not move.
It pays to be cautious, as a program like this is not guaranteed to crash even if you have a bug, as the old data may still exist in memory even when your vector resizes. So if you try capturing this and don't see any issues at runtime it does not mean that your program is correct.
For a straight forward solution, I'd look at allocating your objects on the heap using one of the smart pointer types such as std::unique_ptr or std::shared_ptr.

Calling a method of a *shared_ptr* - what happens to reference count?

I am trying to identify a nasty bug where an object spontaneously gets corrupted while being inside a map, and after some hours of debugging, I think I might not have fully grasped the idea of std::shared_ptr.
Here is the Context:
Inside a method, I declare a std::shared_ptr and initialize it to point to a clone of the current object (created by new). Then - after some modifications to the object - I call the same method on that pointer (recursively).
Inside the next recursion of the method, the decision is made to insert this object into a std::unordered_map (which is a class-attribute, so it is available on all recursion levels).
This is some pseudo-code to illustrate what I mean:
class A
{
...
void DoSomething(void); // the recursive function
A* Clone(void) const { return new A(this); } // the clone method
...
static std::unordered_map<std::shared_ptr<A>,int> myMap{};
};
void A::DoSomething(void)
{
...
if (condition) myMap.insert({this,5}); // in a deeper recursive call, condition is true
...
std::shared_ptr<A> pA(Clone()); // make a copy
pA->... // modify it
pA->DoSomething(); // here is the recursive call
...
}
Problem:
Sometimes, the object behind the pointer inside the std::unordered_map is destroyed, and it seems like this happens when the original std::shared_ptr goes out of scope.
My (tentative) understanding: Calling a method of the object the std::shared_ptr points to does not increase the reference count - inside the called method, I have access to this, which is the ptr the std::shared_ptr points to, but what I do with this in there is not affecting the original std::shared_ptr.
To verify this, I added code to make an extra clone into an extra std::shared_ptr, right at the moment of insertion into the map, and then everything works fine (just slower, and uses double the memory, which is both an issue - class A has a lot of complex data).
Question: Is my understanding correct? If not, how would I call a method of a std::shared_ptr so that the this inside the method is still the 'std::shared_ptr'? Or is this not possible, and I have to use another design?
Regarding duplicates: Should we pass a shared_ptr by reference or by value? seems to point that way, but is about passing parameters by value or by reference, which is not a choice I have with the this pointer.
Your understanding is basically correct. This line is your problem:
if (condition) myMap.insert({this,5});
Because of the raw this a completely independent shared_ptr with its own independent reference count is created in this line. Later in the outer recursion level at the end of DoSomething() the original shared_ptr pA goes out of scope, its refcount drops to 0, the object is destroyed and the second shared_ptr in the map starts to dangle.
Solution 1
You can solve it with std::enable_shared_from_this:
class A : public std::enable_shared_from_this<A> { ... }
// Btw: Lose the void pseudo-parameter. This is not C. ;)
void A::DoSomething()
{
if (condition) {
myMap.insert({shared_from_this(), 5});
}
}
Potential Solution 2
From the code snippets you show I find it highly questionable that you need shared_ptr at all. Nothing of what you show indicates shared ownership. If that’s indeed the case, switch to unique_ptrs and std::move() them around. That gets rid of the problem, too.

Construct returned object in calling function's scope

Is it possible to force C++ to construct an object in the scope of a calling function? What I mean is to explicitly do what an return value optimization (RVO) does.
I have some container classes which are in a chain of derivation. Since the classes are constructed with stack data, they can't be returned, so I disabled the copy constructor and assignment operators. For each class, I am providing an iterator. The constructor of each iterator has only one argument: a pointer to the container class. To get the iterator, I want to use this function:
BindPackIterator BindPack.begin(void)
{
return BindPackIterator(this);
}
in this context:
for (auto i=bindpack.begin(); !i.end(); ++i) { i.run(); }
The compiler issues errors, complaining about not being able to copy the BindPackIterator object. Remember, I disabled them.
What I want to happen is for the BindPackIterator to be instantiated in the calling function's scope to avoid either a copy or move operation.
In this particular case, I know I can do a workaround, changing the begin function to return a BindPack pointer,
for(BindPackIterator i=bindpack.begin(); !i.end(); ++i) { i.run(); }
and I've experimented a bit, without success, with decltype and this construction:
auto BindPack::begin(void) -> BindPackIterator
{
return BindPackIterator(this);
}
This is just the example with which I'm currently frustrated. There have been other projects where the obvious solution is for the function to instantiate an object in the calling function's scope. The move constructor (foo&&) helps in some cases, but for objects with many data members, even that can be inefficient. Is there a design pattern that allows object construction/instantiation in the caller's scope?
Putting n.m.'s comment into code, write a constructor for BindPackIterator that takes a BindPack and initializes the iterator in the "begin" state. e.g:
BindPackIterator(BindPack* pack) : pack(pack), pos(0){ }
That you can use in your for loop:
BindPack pack;
for(BindPackIterator i(&pack); !i.end(); ++i){
i.run();
}
Live demo
Is it fair to say that the answer is "No," it is not possible to construct a returned object in the calling function's scope? Or in other words, you can't explicitly tell the compiler to use RVO.
To be sure, it is a dangerous possibility: stack memory used to construct the object while available in the called function will not be valid in the calling function, even though the values might remain untouched in the abandoned stack frame. This would result in unpredictable behavior.
Upon further consideration, while summing up at the end of this response, I realized that the compiler may not be able to accurately predict the necessary stack size for objects created in the calling function and initialized in a called function, and it would not be possible to dynamically expand the stack frame if the execution had passed to another function. These considerations make my whole idea impossible.
That said, I want to address the workarounds that solve my iterator example.
I had to abandon the idea of using auto like this:
for (auto i=bindpack.begin(); !i.end(); ++i)
Having abandoned auto, and realizing that it's more sensible to explicitly name the variable anyway (if the iterator is different enough to require a new class, it's better to name it to avoid confusion) , I am using this constructor:
BindPackIterator(BindPack &ref) : m_ref_pack(ref), m_index(0) { }
in order to be able to write:
for (BindPackIterator i=bindpack; !i.end(); ++i)
preferring to initialize with an assignment. I used to do this when I was last heavily using C++ in the late 1990's, but it's not been working for me recently. The compiler would ask for a copy operator I didn't want to define for reasons stated above. Now I think that problem was due to my collection of constructors and assignment operators I define to pass the -Weffc++ test. Using simplified classes for this example allowed it to work.
Another workaround for an object more complicated than an iterator might be to use a tuple for the constructor argument for objects that need multiple variables to initialize. There could be a casting operator that returns the necessary tuple from the class that initializes the object.
The constructor could look like:
FancyObject(BigHairyTuple val) : m_data1(get<0>(val)), m_data2(get<1>(val), etc
and the contributing object would define this:
class Foo
{
...
operator BigHairyTuple(void) {
return BigHairyTuple(val1, val2, ...);
}
};
to allow:
FancyObject fo = foo;
I haven't tested this specific example, but I'm working with something similar and it seems likely to work, with some possible minor refinements.

inserting temporary std::shared_ptr into std::map, is it bad?

I'm designing a class for my application that implements a lot of standard shared pointers and usage of standard containers such as std::map and std::vector
It's very specific question to the problem so I just copied a piece of code
from my header for clarification purposes..
here is a snapshot of that declarations from the header:
struct Drag;
std::map<short, std::shared_ptr<Drag>> m_drag;
typedef sigc::signal<void, Drag&> signal_bet;
inline signal_bet signal_right_top();
and here is one of the functions that uses the above declarations and a temporary shared_ptr which is intended to be used not only in this function but until some late time. that means after the function returns a shared pointer should be still alive because it will be assigned at some point to another shared_ptr.
void Table::Field::on_signal_left_top(Drag& drag)
{
m_drag.insert(std::make_pair(drag.id, std::make_shared<Drag>(this))); // THIS!
auto iter = m_drag.find(drag.id);
*iter->second = drag;
iter->second->cx = 0 - iter->second->tx;
iter->second->cy = 0 - iter->second->ty;
invalidate_window();
}
the above function first insert a new shared_ptr and then assigns the values from one object into another,
What I need from your answer is to tell whether is it safe to insert temporary shared_ptr into the map and be sure that it will not be a dangling or what ever bad thing.
According to THIS website the above function is not considered safe because it would much better to write it like so:
void Table::Field::on_signal_left_top(Drag& drag)
{
std::shared_ptr pointer = std::make_shared<Drag>(this);
m_drag.insert(std::make_pair(drag.id, pointer));
auto iter = m_drag.find(drag.id);
*iter->second = drag;
// etc...
}
well one line more in the function.
is it really required to type it like that and why ?
There's no difference between the two functions in regard to the std::shared_ptr, because the std::make_pair function will create a copy of the temporary object before the temporary object is destructed. That copy will in turn be copied into the std::map, and will then itself be destructed, leaving you with a copy-of-a-copy in the map. But because the two other objects have been destructed, the reference count of the object in the map will still be one.
As for handling the return value from insert, it's very simple:
auto result = m_drag.insert(...);
if (!result.second)
{
std::cerr << "Could not insert value\n";
return;
}
auto iter = result.first;
...
The code in the example given is different from your example code, because it is using the new operator instead of std::make_shared. The key part of their advice is here:
Since function arguments are evaluated in unspecified order, it is possible for new int(2) to be evaluated first, g() second, and we may never get to the shared_ptr constructor if g throws an exception.
std::make_shared eliminates this problem - any dynamic memory allocated while constructing an object within std::make_shared will be de-allocated if anything throws. You won't need to worry about temporary std::shared_ptrs in this case.

isn't iterator an object?

this is my code:
for (list<moveStringTree>::iterator tempIterator=moveList.begin();tempIterator!=moveList.end(); ++tempIterator)
{
moveStringTree *move = tempIterator;
}
but it gives me an error. if there is a castingway, I don't like it. it is too time consuming. anyway I want to go throw a list and do something with each object in it. what can I do?
foreach won't help. because only it will give a copy.
isn't iterator an object?
It is. An object in C++ is equivalent to a memory location holding a value – no more, no less. However, I don’t see how this relates to the rest of the question.
but it gives me an error. if there is a castingway, I don't like it. it is too time consuming.
I have no idea what this means. But just in case you meant copy: no, it’s probably not too time-consuming. But if it is – don’t worry; use a reference.
moveStringTree& move = *tempIterator;
foreach won't help. because only it will give a copy.
Nonsense. foreach does the same as manually iterating. So you can also use it with a copy:
for (auto& o : moveList) {
// Do something.
}
You can use an iterator as if it was a pointer, but it isn't actually one. There is a dance that you can do to grab a pointer out of it, though:
moveStringTree *move = &*tempIterator;
The * resolves to a reference to the element that the iterator refers to, and the & returns the address of that element. The end result is a pointer.
Of course, you probably shouldn't do that. This:
tempIterator->doSomething();
works just fine.
Try:
moveStringTree *move = & (*tempIterator) ;
(the parentheses aren't strictly necessary)
The iterator itself is not a pointer to the object, but overloads * to return a reference to the object it refers to; from it you can get a pointer using the normal &.
Notice that normally you don't need to do this, since the iterator overloads also the -> operator, so you can access the object's members using the usual -> syntax.
In fact, you can gain a reference from std::for_each. moveStringTree* move = &*tempIterator; would be correct. However, more directly, you can simply use tempIterator as if it was already a pointer to the object in question.
for(auto it=moveList.begin();it!=moveList.end(); ++it) {
it->f(); // well formed if moveStringTree::f()
}