I have a pointer to an object. I would like to store it in two containers which both have the ownership. So I think I would be good to make it a shared_ptr of C++0x. How could I convert a raw pointer to a shared_pointer?
typedef unordered_map<string, shared_ptr<classA>>MAP1;
MAP1 map1;
classA* obj = new classA();
map1[ID] = how could I store obj in map1??
Thanks
You need to make sure you don't initialize both shared_ptr objects with the same raw pointer, or it will be deleted twice. A better (but still bad) way to do it:
classA* raw_ptr = new classA;
shared_ptr<classA> my_ptr(raw_ptr);
// or shared_ptr<classA> my_ptr = raw_ptr;
// ...
shared_ptr<classA> other_ptr(my_ptr);
// or shared_ptr<classA> other_ptr = my_ptr;
// WRONG: shared_ptr<classA> other_ptr(raw_ptr);
// ALSO WRONG: shared_ptr<classA> other_ptr = raw_ptr;
WARNING: the above code shows bad practice! raw_ptr simply should not exist as a variable. If you directly initialize your smart pointers with the result of new, you reduce your risk of accidentally initializing other smart pointers incorrectly. What you should do is:
shared_ptr<classA> my_ptr(new classA);
shared_ptr<classA> other_ptr(my_ptr);
What's nice is that the code is more concise as well.
EDIT
I should probably elaborate on how it would work with a map. If you had a raw pointer and two maps, you could do something similar to what I showed above.
unordered_map<string, shared_ptr<classA> > my_map;
unordered_map<string, shared_ptr<classA> > that_guys_map;
shared_ptr<classA> my_ptr(new classA);
my_map.insert(make_pair("oi", my_ptr));
that_guys_map.insert(make_pair("oi", my_ptr));
// or my_map["oi"].reset(my_ptr);
// or my_map["oi"] = my_ptr;
// so many choices!
You can use a variety of ways, but reset() would be good:
map1[ID].reset(obj);
And to address the issue of having two maps refer to the same shared_ptr, we can have:
map2[ID] = map1[ID];
Note that the trick in general to avoid a double delete is to try to avoid raw pointers at all.
Hence avoid:
classA* obj = new classA();
map1[ID].reset(obj);
but instead put the new heap object straight into a shared_ptr.
Related
I have the below bit of code:
map<int,int>& myMap = new map<int,int>();
but I get the following compiler error:
no suitable constructor exists to convert from "std::map<int,int, std::less<int>, std::allocator<std::pair<const int, int>>>*" to "std::map<int,int, std::less<int>, std::allocator<std::pair<const int, int>>>".
Does this mean I have to do:
map<int,int>& myMap = *new map<int,int>();
I thought that objects could passed to references without dereferencing first (as opposed to pointers)? Also I know smart pointers exist but I'm not trying to use those for now.
You can use
map<int,int>& myMap = *new map<int,int>();
but I don't recommend it.
The dynamically allocated memory has to be deallocated. At that time, you will need to use something along the lines of
delete &myMap;
That is poor quality code, IMO.
Use a smart pointer if you need dynamically allocated memory.
std::shared_ptr<map<int,int>> ptr = new map<int,int>();
If you need to use a reference, you can use:
map<int,int>& myMap = *ptr;
It will better if you can avoid dynamically allocated object altogether and use an automatic object (object in stack memory).
map<int,int> myMap;
Update, in response to OP's comment
In a comment you said
Yeah i want to keep that reference because im passing it to a recursive function
The C++ way to deal with it is to pass an object by reference.
void recursive_foo(std::map<int, int>& myMap)
{
}
void foo_user()
{
std::map<int, int> myMap;
// Fill up myMap
// ...
recursive_foo(myMap);
}
If the recursive function does not modify the object, you can follow the idiom used by the standard library and use iterators instead.
void recursive_foo(std::map<int, int>::iterator start,
std::map<int, int>::iterator end)
{
}
void foo_user()
{
std::map<int, int> myMap;
// Fill up myMap
// ...
recursive_foo(myMap.begin(), myMap.end());
}
I thought that objects could passed to references without dereferencing first (as opposed to pointers)?
Yes objects can be passed, but what you have here:
map<int,int>& myMap = new map<int,int>();
is not an object but reference which you try to initialize by pointer to dynamically allocated object. Just create object:
map<int,int> myMap;
and it should work fine.
To make things clear, you mixed different concepts, lets say we have a function that accepts variable of sometype by reference:
void func( sometype &ref ) { ... }
it does not mean you have to declare variable as reference to pass it there, you can pass automatic object:
sometype auto_object;
func( auto_object );
or pass dynamically allocated one:
sometype *ptr_to_object = new sometype;
func( *ptr_to_object );
delete ptr_to_object; // or better use smart pointer
and if you do not need this object to outlive scope where you use it it is preferable to use first variant.
I have a vector pointer that points to a vector<object> so
const std::vector<object> vecPtr* = &vec;
Now i'd like to fill in this manner std::multimap<std::string, object*> dataMap; where the key is object.name and value is pointer to an object.
I tried
for(std::vector<object>::const_iterator it = data->cbegin(); it != data->cend(); ++it){
dataMap.insert(std::pair<std::string, object*>(it->name, &it));
}
but i get an error.
error: no matching function for call to 'std::pair<std::basic_string<char>, object*>::pair(const string&, std::vector<object>::const_iterator*)'
dataMap.insert(std::pair<std::string, object*>(it->name, &it));
^
What am i doing wrong?
I know i complicating my life with pointers, but I want to avoid copying objects
In order to avoid copying objects consider to use reference of objects. Moreover, consider to use shared pointer such as std::shared_ptr (for C++11), or boost::shared_ptr. A good style is to avoid allocating memory manually. Let's do it in an automatic way provided by the STL.
class Object{};
typedef boost::shared_ptr < Object > ObjectPtr;
then
std::multimap < std::string, ObjectPtr > map;
Creating instances of Object just use:
ObjectPtr obj = boost::make_shared < Object > ();
&it is a pointer to iterator, not to an object. If you want to get a pointer to an object, write &*it.
After that you'll see an error saying that you can't convert from const object* to object* - this is because you are using const_iterator. So, depending on what you need, you can do two things.
Either declare dataMap as std::multimap<std::string, const object*> dataMap;, if you are not planning to change the objects in it.
Or use iterator:
for (std::vector<object>::iterator it = data->begin(); it != data->end(); ++it) {
dataMap.insert(std::pair<std::string, object*>(it->name, &*it));
}
By the way, this loop can be rewritten as:
for (auto& a : *data) {
dataMap.insert({a.name, &a});
}
I have the following structure:
typedef Memory_managed_data_structure T_MYDATA;
std::vector<T_MYDATA *> object_container;
std::vector<T_MYDATA *> multiple_selection;
T_MYDATA * simple_selection;
Edit: this may be very important: the Memory_managed_data_structure contains, among other things, a bitter, raw pointer to some other data.
It aims to be a very simple representation of an original container of memory managed objects (object_container) and then a "multiple_selection" array (for selecting many objects in the range and doing various operations with them) and a "simple_selection" pointer (for doing these operations on a single object).
The lifetime of all objects is managed by the object_container while multiple_selection and simple_selection just point to some of them. multiple_selection and simple_selection can be nullified as needed and only object_container objects can be deleted.
The system works just fine but I am trying to get into shared_ptrs right now and would like to change the structure to something like:
typedef Memory_managed_data_structure T_MYDATA;
std::vector<std::shared_ptr<T_MYDATA> > object_container;
std::vector<std::shared_ptr<T_MYDATA> > multiple_selection;
std::shared_ptr<T_MYDATA> simple_selection;
Again, the object container would be the "owner" and the rest would just point to them. My question is, would this scheme wreak havok in the application?. Is there something I should know before snowballing into these changes?. Are not shared_ptr the appropriate kind of pointer here?.
I can somewhat guarantee that no object would exists in multiple_selection or simple_selection if it is not in object_container first. Of course, no delete is ever called in multiple_selection or simple_selection.
Thanks for your time.
Edit: Forgot to mention, never used any of these automated pointers before so I may be wildly confused about their uses. Any tips and rules of thumb will be greatly appreciated.
You say, that the object container would be the "owner" of the objects in question. In that case, that you have a clear owning relationship, using std::shared_ptr is not ideal. Rather, stick with what you have.
However, if you cannot guarantee, that a pointer has been removed from multiple_selection and/or simple_selection before it is deleted, you have to act. One possible action could be, that you use shared_ptr. In that case, an object could still continue to exist in one of the selections, even, if it is removed (via shared_ptr::reset or just assigning a null value) from object_container.
The other alternative is to make sure, that objects get removed thoroughly: If something is to be deleted, remove ALL references to it from the selections and from the object_container, and THEN delete it. If you strictly follow this scheme, you don't need the overhead of shared_ptr.
I can somewhat guarantee that no object would exists in
multiple_selection or simple_selection if it is not in
object_container first.
If you 150% sure, than there is no need for smart ptr.
Reason you may need it in this situation is debug, I think.
In case you describe - multiple_selection and simple_selection is not shared_ptr, but weak_ptr.
Code with error:
std::vector<int*> owner_vector;
std::vector<int*> weak_vector;
int* a = new int(3);
owner_vector.push_back(a);
weak_vector.push_back(a);
std::for_each(
owner_vector.begin(),
owner_vector.end(),
[](int* ptr) {
delete ptr;
}
);
std::for_each(
weak_vector.begin(),
weak_vector.end(),
[](int* ptr) {
*ptr = 3; // oops... usage of deleted pointer
}
);
You can catch it with smart pointers:
std::vector<std::shared_ptr<int>> owner_vector;
std::vector<std::weak_ptr<int>> weak_vector;
{
auto a = std::make_shared<int>();
owner_vector.push_back(a);
weak_vector.push_back(a);
}
std::for_each(
owner_vector.begin(),
owner_vector.end(),
[](std::shared_ptr<int>& ptr) {
ptr.reset(); // memory delete
}
);
std::for_each(
weak_vector.begin(),
weak_vector.end(),
[](std::weak_ptr<int>& ptr) {
assert(!ptr.expired()); // guarantee to be alive
auto shared_ptr = ptr.lock();
*shared_ptr = 3;
}
);
In last example you will have assert failed, but not undefined/segmentation fault. In not debug case you can disable shared_ptr overhead.
I am using std::map to map string values to MyType *. My map declaration looks like this:
map<string, MyType *> *my_map = new map<string, MyType>;
my_map is a private member variable of one of my classes. My problem is that I am unsure of how to destroy the map. When deleteing the map, I would also like to call delete on all of the MyType * contained in the map. Here is my current destructor:
my_map->erase(my_map->begin(), my_map->end());
delete my_map;
Will this delete the pointers contained in the map, or do I need to iterate through the map to delete each pointer before calling erase?
Pointers merely point. When using raw pointers, you need to know which part of your app owns the resources that the pointers point to. If they are owned by the map, you will need to iterate over the map and call delete on each pointer before the map is destroyed. But if the map just holds pointers to objects that are owned by other parts of your code, you don't need to do anything.
A safer solution is to use shared_ptr to manage object lifetime, which will ensure that the object gets deleted properly when the last shared_ptr is destroyed. You can store shared_ptrs inside the map and if no other shared_ptr instances reference the objects within the map, the objects will be destroyed when the map is destroyed, as desired.
If you use smart pointers instead of raw pointers, everything will be cleaned up for you automatically.
// header:
using MapType = std::map<std::string, std::shared_ptr<MyType>>;
shared_ptr<MapType> my_map;
// usage:
my_map.emplace("foo", std::make_shared<MyType>());
// destructor:
MyClass::~MyClass()
{
// nothing!
}
Will this delete the pointers contained in the map [...]?
No, given the code you have provided, you will leak every member of the map.
As a rule, for every new there must be a matching delete. You have a delete for the map, but none for the elements within.
The most correct solution to this problem is to not use dynamic allocation at all. Just store MyTypes directory, if possible:
map<string, MyType>
... and instead of dynamically allocating the map itself, store that automatically:
map<string,MyType> my_map;
If automatic storage duration is not possible for some reason, then use a smart pointer for the dynamic allocations. Given a C++11 compiler, use unique_ptr (or, rarely, shared_ptr or even weak_ptr) for the elements in the map:
map<string, unique_ptr<MyType>> my_map;
(Given a C++03 compiler, use the Boost equivalents thereof.) Then when my_map is destroyed, all the elements will be deleted.
Baring all of this, if you are in a situation where none of the above will work for you (I would by highly suspect), then you will need to iterate the map youself:
struct deleter
{
template <typename T> operator() (const T& rhs) const
{
delete rhs.second;
}
};
for_each (my_map->begin(), my_map->end(), deleter());
In C++11, this could be made a lambda, something along the line of:
for_each (my_map->begin(), my_map->end(), [](auto item) -> void
{
delete item.second;
});
In modern C++, just make your life easier and use pointers only if strictly required.
You started with this code:
map<string, MyType *> *my_map = new map<string, MyType>;
The first thing you can do is to consider using a std::map instance as data member, instead of a pointer to it.
Then, if MyType is not super-expensive to copy and its instances are only owned by the map, just consider a simple map from string to MyType (instead of MyType*):
// my_map data member - no pointers --> automatically deleted in class destructor
map<string, MyType> my_map;
If you really need a map containing pointers, consider using smart pointers, like std::shared_ptr (available in C++11/14) for shared ownership, or std::unique_ptr for unique non-shared ownership.
(If you target C++98/03, an option is to use boost::shared_ptr. Since there is no move semantics, you can't have unique_ptr, which is heavily based on the move semantics feature.)
e.g.:
// Map containing _smart_ pointers
// --> default destructor is fine (no need for custom delete code)
map<string, shared_ptr<MyType>> my_map;
As you can see, using value semantics (instead of raw pointers), or smart pointers, you can simplify your code and use the automatic destruction provided by C++.
I'm a long-time reader, and first-time poster... I've searched long and hard to find an answer to something that's really boggling my mind right now. I must be missing something, as I believe this should work...
I'm trying to create a datatable class that will contain it's own copies of the objects passed to it. I've decided to use std::map's to contain this data. See the example code below:
typedef std::map <std::string, myVar *> myVarContainer;
class myObj
{
public:
myObj(void);
virtual ~myObj(void);
void setVar(std::string Key, myVar & Var);
myVar * getVar(std::string Key);
void release()
{
for (myVarContainer::iterator i = VarContainer->begin(); i != VarContainer->end(); ++i)
{
delete (i->second);
}
VarContainer->clear();
};
myVarContainer * VarContainer;
};
typedef std::map <myVar, myObj *> myRow;
class myTable
{
public:
myTable(void);
virtual ~myTable(void);
void addDataPoint(myVar RowID, myVar ColID, myObj * Data)
{
std::map <myVar, myRow *>::iterator i = m_Rows->find(RowID);
if (i == m_Rows->end())
{
m_Rows->insert(make_pair(RowID, new myRow()));
}
i = m_Rows->find(RowID);
// i thought the below line would be creating a copy of the data?
// I thought this logic went:
// 1. create a new object copied from the value of 'Data'
// 2. return a pointer to this object and pair with the 'colID'
// 3. make this into a pair and insert into the main map
i->second->insert(make_pair(ColID, new myObj(*Data)));
};
protected:
std::map <myVar, myRow *> * m_Rows;
}
int main()
{
myVar a, b, c, d;
myObj * o = new myObj();
o->setVar("test", a);
o->setVar("test2", b);
myTable * tab = new myTable();
myVar x1, y1, x2;
tab->addDataPoint(y1, x1, o);
o->release(); // this clears out both 'o' and the values in 'tab'!?!?
//at this point tab has no data in its object at y1,x1???
o->setVar("test3", c);
o->setVar("test4", d);
tab->addDataPoint(y1, x2, o);
}
What I'm noticing is that my data is deleted too early. I believe I've missed something... I had thought I was creating a copy of the data referenced by the pointer and then storing a newly instance'd pointer in my map... Any thoughts? I appreciate any help!
So one of the problems that using (owning) raw pointers in containers is that you need to manually delete the instances yourself. I presume that myObj::~myObj does just that (iterates the container deleting all elements before deleting the container itself).
The line:
i->second->insert(make_pair(ColID, new myObj(*Data)));
Is copy constructing a myObj from Data.
Unfortunately, because you are not defining a copy constructor for myObj the compiler will generate one for you which will just copy the pointer to the VarContainer member. It won't create a new copy of the map or anything that it refers to internally. Once a copy is created you then have two instances which both point to the same container and both instances think that they own it. When the first one gets destructed it will seem to ok but actually leaves the other instance pointing to freed memory. As soon as the longest lived instance tries to do anything using this container pointer something bad will happen.
You could fix this by storing the maps by value and not by pointer:
typedef std::map<std::string, myVar> myVarContainer;
typedef std::map<myVar, myObj> myRow;
Also change myObj::VarContainer to be a non-allocated member. This means that everything now gets copied correctly and a copy will not reference anything from the original.
Note that you can also use smart pointers (such as std::shared_ptr) instead of raw pointers but you will still need to be careful with that as, although copying would be safe, they share data with the original which might not be what you expect.
You should take a look at the following:
http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
It seems that you are indeed creating a copy of the object, but then when you release(), you are releasing the VarContainer (deleting all items and using clear()), so the copy you created before (with a copy of the pointer, not the actual container) is left with a pointer to an empty container.