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

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.

Related

If a function returns a std::unique_ptr, is it reasonable to assume each returned value is to a new object?

I'm learning about std::unique_ptr, trying to grok what it represents.
Given a function (out of my control) that returns a unique_ptr, is it implied/well understood that each invocation returns a unique_ptr that points to a new object (different than any prior invocation)?
By way of example, the following code produces a double-free on exit, and I hope that I correctly understand why: unique_ptrs delete their underlying object on destruction; therefore two unique_ptrs encapsulating the same memory/object would cause a double-free on destruction of the second. Therefore, would the following implementation of function getUniquePtr() be commonly/implicitly understood to be unreasonable?
// main.cpp
#include <memory>
#include <iostream>
std::unique_ptr<int> getUniquePtr() {
static int* p = new int(42);
return std::unique_ptr<int>(p);
}
class PtrOwner {
public:
std::unique_ptr<int> p_;
};
int main( int argc, char* argv[] ) {
PtrOwner po1;
PtrOwner po2;
po1.p_ = getUniquePtr();
po2.p_ = getUniquePtr();
return 0;
}
It should be assumed that, if a function returns std::unique_ptr<T>, then the returned smart pointer points to an object that is not currently managed by anyone else. This does not necessarily mean that it always refers to a different object. So long as this convention is followed, double-free bugs will be avoided. If this convention is violated, double-free bugs will occur.
For example, if you see some function like this:
std::unique_ptr<T> foo(std::unique_ptr<T> arg);
This function might, potentially, return std::move(arg) under some circumstances or it might destroy arg and return some other pointer. (You have to read the documentation to know what it does). This implies that you could do something like this:
auto t = std::make_unique<T>();
t = foo(std::move(t));
t = foo(std::move(t));
In this case, foo might just return the same pointer value twice, and this is perfectly safe. This example seems silly, but hopefully it gets my point across.
Yes, your assumptions are (mostly) correct. A unique_ptr owns the object exclusively, which implies that no two unique_ptrs should point to the same object at any given time.
As others have pointed out, this does not guarantee that multiple invocations of the same function returns different objects. This is because you can pass ownership around (by moving it), so if you pass ownership back to a function, as in Brians answer, it may well return the same object again, without braking any rules.
If you decide to manage an object by using smart pointers, try to avoid new and delete altogether. To create an object T that is owned by a unique_ptr, use make_unique<T>. This avoids the error of creating multiple unique_ptr to the same object. A unique_ptr is not copyable for exactly this reason. In other words, your getUniquePtr should be implemented like this:
return std::make_unique<int>(42);
One of the few reasons to construct a smart pointer from a raw pointer (as opposed to using make_unique) is when you have existing code or a library that works with raw pointers, which you cannot change.

Reference type return function: how to return (optional) object

I've a multithreaded C++ application that could call from any thread a function like the following, to get an Object from a list/vector.
class GlobalClass{
public:
MyObject* GlobalClass::getObject(int index) const
{
/* mutex lock & unlock */
if (m_list.hasValueAt(index))
return m_list[index];
else
return 0;
}
List<MyObject*> m_list;
};
//Thread function
MyObject* obj = globalClass->getObject(0);
if (!obj) return;
obj->doSomething();
Note: the scope here is to understand some best practice related to function returns by reference, value or pointer, so forgive some pseudo-code or missing declarations (I make use of lock/unlock, GlobalClass is a global singleton, etc...).
The issue here is that if the MyObject at that index in deleted inside GlobalClass, at a certain point I'm using a bad pointer (obj).
So I was thinking about returning a copy of the oject:
MyObject GlobalClass::getObject(int index) const
{
/* mutex lock & unlock */
if (m_list.hasValueAt(index))
return MyObject(*m_list[index]);
else
return MyObject();
}
The issue here is that the object (MyObject) being returned is a large enough object that returning a copy is not efficient.
Finally, I would like to return a reference to that object (better a const reference):
const MyObject& GlobalClass::getObject(int index) const
{
/* mutex lock & unlock */
if (m_list.hasValueAt(index))
return *m_list[index];
else{
MyObject* obj = new MyObject();
return *obj ;
}
}
Considering that my list couldn't cointain the object at that index, I'm introducing a memory leak.
What's the best solution to deal with this?
Must I fall back in returning a copy even if is less efficient or is there something I'm missing in returning a reference?
You have multiple choices:
Use a std::shared_ptr if "Get" pass the owning of the object to the caller. This way the object cannot get out of scope. Of course the caller is unaware when it happens.
Use a std::weak_ptr. This has the same meaning of 1., but the ptr can be reset. In this case the caller can detect if the object was deleted.
Use std::optional as suggested in a comment, and return a copy or a reference. The use of a reference type as argument of optional doesn't avoid the problem of the object being deleted so the reference can become invalid as well. A copy would avoid this, but it may be too expensive, as said.
Reading through the lines, you seems to suggest that the caller will use the pointer immediately after the call, and for a limited span of time. So 1. and 2. are equivalent and seems to fit your needs.
See this introduction to smart pointers for more details.
If you want to avoid copying the object, there are only two possible cases:
The m_list entry that is returned by getObject is/can be deleted concurrently by another thread. If you don't copy that object beforehand, there is nothing you can do within getObject to prevent another thread from suddenly having a reference/pointer dangle. However, you could make each entry of m_list be a std::shared_ptr<MyObject> and return that directly. The memory management will happen automatically (but beware of the potential overhead in the reference counting of shared_ptr, as well as the possibility of deadlocks).
You have (or add) some mechanism to ensure that objects can only be deleted from m_list if no other thread currently holds some pointer/reference to them. This very much depends on your algorithm, but it might e.g. be possible to mark objects for deletion only and then delete them later in a synchronous section.
Your issues seems to stem from the fact that your program is multithreaded - another way forward (and for raw pointer or the std::optional reference returning version: only way forward, perhaps short of a complete redesign), is that you need to expose the mutex to outside the function scope to accomplish what you need. This you can accomplish in multiple ways, however the most simple way to illustrate this is the following:
/*mutex lock*/
const MyObject& obj = globalClass.get(index);
/*do stuff with obj*/
/*mutex unlock*/

Using boost::shared_ptr to refer to iterator without copying data?

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
}

Which type of pointer to use to implement shared access to elements of a set?

In order to make the discussion clear, I'm going to describe the problem in a very general manner, i.e. I will neither provide names of real classes nor will I describe the domain/context (however, I might if it turns out to be urgent).
Imagine class A. Let this class have 2 immutable fields, for instance x and y (please, notice, that these could be potentially big objects, i.e. inefficient to copy). Additionally, let these x and y be primary fields, i.e. only they are used in the implementation of ==/!= operators as well as hash-computing function.
Since A is immutable in terms of x and y, the idea is to let multiple instances of A (say a1 and a2) which have a1.x == a2.x a1.y == a2.y (i.e. a1 == a2) to implicitly have shared access to those x and y, so that there is no unnecessary duplication.
Moreover, now imagine that there is another field in A: z, which is secondary and mutable, and serves as a sort of behavior tweak for A. By design, it is desired to make this field shared among equal instances of A too. So, if I invoke a1.setZ(...) this change will also affect a2 because their access to z is shared.
As a result, we end up with a class A which has pure value semantics, but shares its members implicitly across equal instances. AFAIK such pattern is called Flyweight or aliasing.
One more detail before we move to the question. Most classes in the project are implemented using Pimpl idiom:
private:
class Private;
Private* p;
and class A is not an exclusion. That's why the proposed idea of implementing the scheme described above is as follows.
Use shared pointer to A::Private instead of raw one in
Pimpl idiom;
Have global set of shared pointers to A::Private;
In constructor of A to check whether a shared
pointer to suitable A::Private already exists in the set
(utilizing x and y of course), and if yes, then simply set p
to it, otherwise create new instance of A::Private and store
shared pointer to it in this set, and similarly set p to it;
A::Private's destructor should remove shared pointer to this from the set.
This looks like the most straightforward and intuitive implementation. However, the problem is that since this global set holds a shared pointer to A::Private, it means that even when all instances of corresponding A are destroyed, the reference counter will stay on 1, i.e. it will never reach 0, and thus the memory is never freed.
I thought it would be good if some shared pointers would offer a method to set lower bound for the reference counter. In this case, for example, I would simply set it to 1 which would mean that when it reaches 1 it frees the memory. Unfortunately, I haven't found any implementation of such behavior in popular libraries (Boost, Qt, Poco, etc.). Of course, I could do manual reference counting for my problem, but that just doesn't feel right and smells like reinventing the wheel.
Probably, there are other ways to solve this problem. Looking forward for your suggestions.
NOTE: I would like to immediately intercept any advising to transform the problem to pointer semantics which I am well aware of. I need the solution exactly for the scheme described above.
If I understood correctly what your design issue is, then I would let the global set contain weak, non-owning pointers (e.g. weak_ptr<>) which are able to check if they are dangling, yet they do not increase the reference count.
std::vector<std::weak_ptr<Private>> _objects;
Therefore, when all owning shared pointers to an object are destroyed, the object will be destroyed as well**.
Now your global set will be left with a dangling weak_ptr<>, but the nice thing is that you can check whether that pointer points to an object which is alive or not (use the lock() member function to obtain a possibly null shared_ptr<>. And if it doesn't, you won't dereference it:
// A simple, hypothetical loop through the collection of objects
// which does something, but checks whether the pointers are
// dangling before doing that something on a possibly dead object
// that would be Undefined Behavior)
std::for_each(_objects.begin(), _objecs.end(), [] (std::weak_ptr<Private> p)
{
std::shared_ptr<Private> sp = p.lock();
if (sp != nullptr)
{
sp->callMember(); // For instance...
}
});
If you also want to remove the corresponding weak_ptr<> to an object from the collection once the object gets destroyed, then you could use a custom deleter routine. Your routine will be invoked when the object is destroyed and will be passed the pointer to that object: at this point, before deallocating, you can erase the corresponding element from the set.
For example, a function that instantiates new objects of type A and returns a shared_ptr to it could look this way:
static std::shared_ptr<object> make_A()
{
std::shared_ptr<Private> sp(
new Private(), // Instantiate the object
[] (Private* p) // Set up the custom deleter...
{
// Remove the corresponding element from the vector...
_objects.erase(
// ...so let's find that element!
std::find_if(
_objects.begin(),
_objects.end(),
[p] (std::weak_ptr<priv> wp)
{
// lock() will return a null pointer if wp is dangling
std::shared_ptr<priv> sp = wp.lock();
// In case wp is not dangling, return true if and only
// if it points to the object we're about to delete
return ((sp != nullptr) && (sp.get() == p));
})
);
});
}
Here I assumed C++11, you could easily do the same in C++03 by replacing std::shared_ptr<> with boost::shared_ptr<>, std::weak_ptr<> with boost::weak_ptr<>, and lambdas with properly-defined functors.
Hope this helps.
Have you checked Boost.Flyweight out?

Is it wrong to dereference a pointer to get a reference?

I'd much prefer to use references everywhere but the moment you use an STL container you have to use pointers unless you really want to pass complex types by value. And I feel dirty converting back to a reference, it just seems wrong.
Is it?
To clarify...
MyType *pObj = ...
MyType &obj = *pObj;
Isn't this 'dirty', since you can (even if only in theory since you'd check it first) dereference a NULL pointer?
EDIT: Oh, and you don't know if the objects were dynamically created or not.
Ensure that the pointer is not NULL before you try to convert the pointer to a reference, and that the object will remain in scope as long as your reference does (or remain allocated, in reference to the heap), and you'll be okay, and morally clean :)
Initialising a reference with a dereferenced pointer is absolutely fine, nothing wrong with it whatsoever. If p is a pointer, and if dereferencing it is valid (so it's not null, for instance), then *p is the object it points to. You can bind a reference to that object just like you bind a reference to any object. Obviously, you must make sure the reference doesn't outlive the object (like any reference).
So for example, suppose that I am passed a pointer to an array of objects. It could just as well be an iterator pair, or a vector of objects, or a map of objects, but I'll use an array for simplicity. Each object has a function, order, returning an integer. I am to call the bar function once on each object, in order of increasing order value:
void bar(Foo &f) {
// does something
}
bool by_order(Foo *lhs, Foo *rhs) {
return lhs->order() < rhs->order();
}
void call_bar_in_order(Foo *array, int count) {
std::vector<Foo*> vec(count); // vector of pointers
for (int i = 0; i < count; ++i) vec[i] = &(array[i]);
std::sort(vec.begin(), vec.end(), by_order);
for (int i = 0; i < count; ++i) bar(*vec[i]);
}
The reference that my example has initialized is a function parameter rather than a variable directly, but I could just have validly done:
for (int i = 0; i < count; ++i) {
Foo &f = *vec[i];
bar(f);
}
Obviously a vector<Foo> would be incorrect, since then I would be calling bar on a copy of each object in order, not on each object in order. bar takes a non-const reference, so quite aside from performance or anything else, that clearly would be wrong if bar modifies the input.
A vector of smart pointers, or a boost pointer vector, would also be wrong, since I don't own the objects in the array and certainly must not free them. Sorting the original array might also be disallowed, or for that matter impossible if it's a map rather than an array.
No. How else could you implement operator=? You have to dereference this in order to return a reference to yourself.
Note though that I'd still store the items in the STL container by value -- unless your object is huge, overhead of heap allocations is going to mean you're using more storage, and are less efficient, than you would be if you just stored the item by value.
My answer doesn't directly address your initial concern, but it appears you encounter this problem because you have an STL container that stores pointer types.
Boost provides the ptr_container library to address these types of situations. For instance, a ptr_vector internally stores pointers to types, but returns references through its interface. Note that this implies that the container owns the pointer to the instance and will manage its deletion.
Here is a quick example to demonstrate this notion.
#include <string>
#include <boost/ptr_container/ptr_vector.hpp>
void foo()
{
boost::ptr_vector<std::string> strings;
strings.push_back(new std::string("hello world!"));
strings.push_back(new std::string());
const std::string& helloWorld(strings[0]);
std::string& empty(strings[1]);
}
I'd much prefer to use references everywhere but the moment you use an STL container you have to use pointers unless you really want to pass complex types by value.
Just to be clear: STL containers were designed to support certain semantics ("value semantics"), such as "items in the container can be copied around." Since references aren't rebindable, they don't support value semantics (i.e., try creating a std::vector<int&> or std::list<double&>). You are correct that you cannot put references in STL containers.
Generally, if you're using references instead of plain objects you're either using base classes and want to avoid slicing, or you're trying to avoid copying. And, yes, this means that if you want to store the items in an STL container, then you're going to need to use pointers to avoid slicing and/or copying.
And, yes, the following is legit (although in this case, not very useful):
#include <iostream>
#include <vector>
// note signature, inside this function, i is an int&
// normally I would pass a const reference, but you can't add
// a "const* int" to a "std::vector<int*>"
void add_to_vector(std::vector<int*>& v, int& i)
{
v.push_back(&i);
}
int main()
{
int x = 5;
std::vector<int*> pointers_to_ints;
// x is passed by reference
// NOTE: this line could have simply been "pointers_to_ints.push_back(&x)"
// I simply wanted to demonstrate (in the body of add_to_vector) that
// taking the address of a reference returns the address of the object the
// reference refers to.
add_to_vector(pointers_to_ints, x);
// get the pointer to x out of the container
int* pointer_to_x = pointers_to_ints[0];
// dereference the pointer and initialize a reference with it
int& ref_to_x = *pointer_to_x;
// use the reference to change the original value (in this case, to change x)
ref_to_x = 42;
// show that x changed
std::cout << x << '\n';
}
Oh, and you don't know if the objects were dynamically created or not.
That's not important. In the above sample, x is on the stack and we store a pointer to x in the pointers_to_vectors. Sure, pointers_to_vectors uses a dynamically-allocated array internally (and delete[]s that array when the vector goes out of scope), but that array holds the pointers, not the pointed-to things. When pointers_to_ints falls out of scope, the internal int*[] is delete[]-ed, but the int*s are not deleted.
This, in fact, makes using pointers with STL containers hard, because the STL containers won't manage the lifetime of the pointed-to objects. You may want to look at Boost's pointer containers library. Otherwise, you'll either (1) want to use STL containers of smart pointers (like boost:shared_ptr which is legal for STL containers) or (2) manage the lifetime of the pointed-to objects some other way. You may already be doing (2).
If you want the container to actually contain objects that are dynamically allocated, you shouldn't be using raw pointers. Use unique_ptr or whatever similar type is appropriate.
There's nothing wrong with it, but please be aware that on machine-code level a reference is usually the same as a pointer. So, usually the pointer isn't really dereferenced (no memory access) when assigned to a reference.
So in real life the reference can be 0 and the crash occurs when using the reference - what can happen much later than its assignemt.
Of course what happens exactly heavily depends on compiler version and hardware platform as well as compiler options and the exact usage of the reference.
Officially the behaviour of dereferencing a 0-Pointer is undefined and thus anything can happen. This anything includes that it may crash immediately, but also that it may crash much later or never.
So always make sure that you never assign a 0-Pointer to a reference - bugs likes this are very hard to find.
Edit: Made the "usually" italic and added paragraph about official "undefined" behaviour.