I have a code snippet that uses std::map::emplace to insert elements into a map. The key is an internal version of a unique_ptr.
The standard states:
The element may be constructed even if there already is an element with the key in the container, in which case the newly constructed element will be destroyed immediately.
In the following snippet, if the wrapper is constructed/destructed, it will correctly take destroy the naked pointer. If it is not, the object will be leaked. The snippet is just an example.
class Wrapper {
public:
Wrapper(int* param):
value(param) {}
~Wrapper() { delete value;}
bool operator<(const Wrapper& other) const { return *value < *other.value;}
private:
int * value;
};
int main()
{
std::map<Wrapper, int> map;
{
int *key = new int(100);
map.emplace(key, 5);
}
{
int *keyDuplicate = new int(100);
map.emplace(keyDuplicate, 10);
}
}
The handling seems to be implementation dependant. I could check the return value and destroy the object if it was a duplicate. But if the object was constructed and deleted, I would be deleting the pointer twice.
Related
Lets say I have the following:
int main() {
int* test = new int;
*test = 5;
int* test2 = test;
}
Then, somewhere, in some function , I deallocate memory for test2 and set it to NULL. Is there a way to set test to NULL, in the same function without passing it to the function?
EDIT: std::shared_ptr cannot be used
The shared_ptr and weak_ptr classes do exactly what you want. Since you can't use them, your best option is to re-implement just the portions of them that you need. I'm going to assume you don't need any thread safety and that you don't care about optimizations for simplicity. If you do, use the standard library.
You need a control object. It should have a pointer to the real object and two integers, one the count of strong pointers, the other the count of weak pointers. Strong pointers and weak pointers should have a pointer to the control object.
When a strong pointer is destroyed, decrement the strong pointer count. If the strong pointer count is zero, delete the object and set its pointer to NULL. If the weak pointer count is also zero, discard the control object.
When a weak pointer is destroyed, decrement the weak pointer count. If both pointers counts are zero, discard the control object.
When pointers are copied, you must bump the count. When a weak pointer is promoted to a strong pointer, bump the strong pointer count and fail the operation if it was previously zero.
That should be enough to give you the idea.
Pass the pointer be reference, since a copy would be passed to the function had you used a normal pointer, on which you can only change the pointed value, and since both pointers point to the same thing, no need to call change() on both:
#include <iostream>
void change(int*& p)
{
delete p;
p = nullptr;
}
int main()
{
int* test = new int;
*test = 5;
int* test2 = test;
std::cout << *test; //5
std::cout << *test2; //5
change(test);
}
Example
BTW, I recommend std::shared_ptr for a purpose like this, or std::unique_ptr
EDIT
The only problem above is that test2 is deleted, not pointing to nullptr, but that cannot be changed unless with smart pointers or a different function.
By default, when you pass a pointer to a function, you are passing a copy of the value:
void f(int* p) {
// p has the same value as x below, but is independent
delete p;
p = nullptr;
// p is null, but back in main 'x' still has the original value
}
int main() {
int* x = new int;
f(x);
// 'x' is unmodified and now points to a deleted block of memory
}
Your options are to pass the pointer by reference or pass a pointer to the pointer:
#include <iostream>
void by_pointer(int** p) {
delete *p;
*p = nullptr;
}
void by_reference(int*& p) {
delete p;
p = nullptr;
}
int main() {
int* x = new int;
by_pointer(&x);
std::cout << (void*)x << "\n"; // outputs null
int* y = new int;
by_reference(y);
std::cout << (void*)y << "\n"; // outputs null
}
If you really want this (though I'd strongly suggest you to reconsider your design), then the following might work for you:
We wrap the pointer in a structure/class to be able to "hook" us on construction and destruction of such pointers:
template<typename T>
struct pointer {
Since when freeing the stored value, we also need to modify all pointers that still point to it, we need to keep track of them somehow. I'd say just store them alongside the value:
struct boxing {
T value;
std::set<pointer<T> *> references;
};
boxing * box;
Next comes constructing a pointer. I simplified here. You might want to add perfect forwarding, a possibility to construct a "null pointer", and so on ...
pointer(T value) : box(new boxing{value}) {
add_myself();
}
As you see, we "add ourselves" (to the set of references). When the pointer is destructed, we need to remove ourselves from that set again:
~pointer() {
remove_myself();
}
When being copy constructed, we just use the box from the original and add ourselves:
pointer(pointer const & p) : box(p.box) {
add_myself();
}
When being copy assigned to, we first need to remove ourselves from the current box, use the box of the original and add ourselves:
pointer & operator=(pointer const & p) {
remove_myself();
box = p.box;
add_myself();
}
I'm lazy. Implement move construction / assignment yourself ;)
pointer(pointer &&) = delete;
pointer & operator=(pointer &&) = delete;
We want to be able to use the pointer, so we add a conversion operator to a raw pointer:
operator T*(void) {
return box ? &(box->value) : nullptr;
}
Finally, freeing a pointer. We set all box members of the current pointers in the references set to nullptr (this includes ourself, thus the additional pointer b), and then delete the box:
void free() {
boxing * b = box;
for (pointer * p : b->references) {
p->box = nullptr;
}
delete b;
}
Oh, and last but not least, adding and removing ourselves:
private:
void remove_myself() {
if (box == nullptr) return;
box->references.erase(this);
if (box->references.size() == 0) {
delete box;
}
}
void add_myself() {
if (box == nullptr) return;
box->references.insert(this);
}
};
Some function. Note that I pass by value to force another copy construction:
void foo(pointer<int> p) {
p.free();
}
Two pointers, pointing to the same boxed value:
int main(int, char **) {
pointer<int> a{21};
pointer<int> b = a;
*b = 42;
std::cout << *a << std::endl;
foo(a);
std::cout << "a is " << ((a == nullptr) ? "null" : "non-null") << std::endl;
return 0;
}
Above example on ideone.
The idea of shared controllers of a uniquely-owned object is of course horrid (for reasons that will become clear).
Nevertheless, it can be done:
template<class T, class Deleter = std::default_delete<T>>
struct shared_unique
{
struct control_block
{
control_block(Deleter del, T* p) : del_(std::move(del)), ptr_(p), refs_(1) {}
Deleter del_;
T* ptr_;
std::size_t refs_;
void addref()
{
++refs_;
}
void release()
{
if (--refs_ == 0)
delete this;
}
~control_block() {
if (ptr_)
del_(ptr_);
}
};
control_block* ctrl_;
shared_unique(T* p = nullptr, Deleter del = Deleter()) : ctrl_(new control_block(std::move(del), p)) {}
shared_unique(shared_unique const& r) : ctrl_(r.ctrl_) { ctrl_->addref(); }
shared_unique& operator=(shared_unique const& r)
{
auto tmp = r;
swap(r);
return *this;
}
shared_unique(shared_unique&& r) : ctrl_(r.ctrl_) { r.ctrl_ = nullptr; }
shared_unique& operator=(shared_unique&& r)
{
auto tmp = std::move(r);
swap(tmp);
return *this;
}
~shared_unique()
{
ctrl_->release();
}
void swap(shared_unique& r) noexcept
{
std::swap(ctrl_, r.ctrl_);
}
void reset(T* p = nullptr)
{
std::swap(ctrl_->ptr_, p);
delete p;
}
T* get() const {
return ctrl_->ptr_;
}
};
int main()
{
shared_unique<int> su1(new int(5));
assert( su1.get() );
assert( *(su1.get()) == 5 );
shared_unique<int> su2 = su1;
assert( su2.get() );
assert( *(su2.get()) == 5 );
su1.reset();
assert( su1.get() == nullptr );
assert( su2.get() == nullptr );
}
The problem is that it is impossible to make this arrangement thread-safe, unless you provide some kind of 'lock' mechanism to keep the pointed-to object alive while it's being accessed.
If you want to know when an object has been destroyed, it's probably better to have it (or its smart pointer) emit a signal when this happens and have the interested observers listen on the slot (or similar).
Bellow I provide the complete code for something really simple which I'm struggling with..
I need to create a map with strings and Objects...
When requested, if the string is inside the map, I need to return a
reference to one object inside the map
When the string is not inside the map, I need to create that object,
with that string and return (as before) the reference to the new
created object
Please check below the two comments I say "ERROR" to see where the problem is.
My questions are:
How can I insert to a map, one object? what is wrong with the line
on the InitObj()?
How can I create return a reference to an object which I've just
created on a map? As seen at the end of getHouse() function
Thanks in advance :)
#include <map>
#include <string>
#include <memory>
class House
{
public:
House(const char* name) : _name(name) {};
~House() {};
std::string getHouseName () { return _name; }
private:
std::string _name;
House(const House& copy)
{
}
House& operator=(const House& assign)
{
}
};
class Obj
{
public:
Obj()
{
InitObj();
}
~Obj() {};
House& getHouse (const char *houseName)
{
std::string name = houseName;
auto i = _myHouseMap.find(name);
//this string doesn't exist on map? then create a new house and add to the map and return the reference to it
if (i == _myHouseMap.end())
{
//create a new house
House h(houseName);
//add to the map
_myHouseMap.insert(std::pair<const std::string, House>(houseName, h));
//return the reference to the house created
return h; //<--- ERROR!!!! need to return the reference!
}
return (i->second);
}
private:
Obj(const Obj& copy);
Obj& operator=(const Obj& assign);
typedef std::map<const std::string, House> myHouseMap;
myHouseMap _myHouseMap;
//the initialization will add one object to my map
void InitObj()
{
House h("apartment");
_myHouseMap.insert(std::pair<const std::string, House>("apartment", h)); //<--- ERROR see reference to function template instantiation 'std::pair<_Ty1,_Ty2>::pair<const char(&)[10],House&>
}
};
int main(void)
{
Obj aaa;
House& myHouse1 = aaa.getHouse ("apartment");
std::cout << "House is " << myHouse1.getHouseName ();
House& myHouse2 = aaa.getHouse ("newHouse"); //here a new house must be created and added to the map
std::cout << "House is " << myHouse2.getHouseName ();
return 0;
}
For your first question, you made House noncopyable (your copy constructor and copy assignment operator are private). The approach you are taking to insert requires you to make a pair first, the construction of which will copy the House you pass in. If you have access to a C++11 compiler, you can still have the value-type of your map be House and just use emplace instead:
void InitObj()
{
_myHouseMap.emplace(std::piecewise_construct,
std::forward_as_tuple("apartment"), //key
std::forward_as_tuple("apartment")); //value
}
If you don't have access to a C++11 compiler, you will have to change the value type to be House* or some equivalent copy-constructible type.
For the second question, std::map::insert (and emplace) return a pair<iterator, bool>. Just take advantage of that:
if (i == _myHouseMap.end())
{
House h(houseName);
// we insert our new house into the map
// insert() will return a pair<iterator, bool>.
// the bool will be true if the insert succeeded - which we know
// it will because we know that this key isn't already in the map
// so we just reassign 'i' to be insert().first, the new iterator
// pointing to the newly inserted element
i = _myHouseMap.insert(std::pair<const std::string, House>(houseName, h)).first;
}
// here i either points to the element that was already in the map
// or the new element that we just inserted. either way,
// we want the same thing
return i->second;
In an effort to become a more competent C++ programmer I'm experimenting w/ using references. In the past I have usually used pointers when referring to objects, as you would for example in Objective-C.
So I've been programming a Polynomial class that stores a list of Term objects
(TermNode* termHead,termTail)
But when I try to add a term to the list using the first implementation listed, calling the constructor on Term in add term, overwrites the Term& reference in the previously created Term node, as if it used the this pointer from the previous invocation of the constructor.
What is technically wrong about the first implementation listed, that causes it to behave so abnormally? It just works when I use pointers and new even though I do not change the structure of TermNode.
struct TermNode {
Term& value;
TermNode* next;
};
Term::Term(int coefficient,int firstTermDegrees,int secondTermDegrees) {
this->coefficient = coefficient;
this->xDegree = firstTermDegrees;
this->yDegree = secondTermDegrees;
}
//Doesn't work
void Polynomial::addTerm(int coefficient, int xDegree, int yDegree) {
Term term(coefficient,xDegree,yDegree);
addTerm(term);
}
void Polynomial::addTerm(Term& term) {
TermNode* t = new TermNode{term,nullptr};
if(isEmpty())
{
termHead = t;
termTail = t;
}
else
{
termTail->next = t;
termTail = termTail->next;
}
}
//Does work
void Polynomial::addTerm(int coefficient, int xDegree, int yDegree) {
Term* term = new Term(coefficient,xDegree,yDegree);
addTerm(term);
}
void Polynomial::addTerm(Term* term) {
TermNode* t = new TermNode{*term,nullptr};
if(isEmpty())
{
termHead = t;
termTail = t;
}
else
{
termTail->next = t;
termTail = termTail->next;
}
}
bool isEmpty() {
return nullptr == termHead;
}
//Doesn't work
void Polynomial::addTerm(int coefficient, int xDegree, int yDegree)
{
Term term(coefficient,xDegree,yDegree);//here you created automatic object
addTerm(term); //it will be deleted in next line
} //it is an error to call addTerm(Term& term)
this works
//Does work
void Polynomial::addTerm(int coefficient, int xDegree, int yDegree)
{
Term* term = new Term(coefficient,xDegree,yDegree);
addTerm(term);
}
because here you created object on a free store. It's life is extended till you call delete on it (side note: call delete somewhere, at this moment you have a memory leak! or use smart pointer), so this works just fine.
void Polynomial::addTerm(Term* term)
{
TermNode* t = new TermNode{*term,nullptr};
// ...
}
You can use references but in the way they are supposed to be used. You can't use a reference to temporary when it was actually deleted. You can bind temporary object to const reference however, but because of your struct definition
struct TermNode
{
Term& value;
TermNode* next;
};
in constructor you take a reference again, so binding temporary to const reference in this case will again result in segmentation fault.
In the first implementation you passes a reference to a temporary object which is destroyed at the end of method addTerm.
I have a map of addresses that allows me to store arbitrary data with objects. Basically, a library I'm writing has a templated function that winds up storing arbitrary data with objects.
std::map<void *, MyUserData>
This works, until the object passed in is destroyed, leaving its user data in the map. I want the associated user data to be removed as well, so I need to somehow listen for the destructor of the passed in object,
Some example code that illustrates the problem:
#include <map>
#include <memory>
struct MyUserData
{
int someNum;
};
std::map<void *, MyUserData> myMap;
template <typename T>
registerObject<T>(const std::shared_ptr<T> & _object)
{
static inc = 0;
myMap[(void *)&_object->get()].someNum = inc++;
}
struct MyObject
{
int asdf;
};
int main(int _argc, char ** _argv)
{
auto obj = std::make_shared<MyObject>();
obj->asdf = 5;
registerObject(obj);
obj = 0;
//The user data is still there. I want it to be removed at this point.
}
My current solution is to set a custom deleter on the shared_ptr. This signals me for when the object's destructor is called, and tells me when to remove the associated user data. Unfortunately, this requires my library to create the shared_ptr, as there is no "set_deleter" function. It must be initialized in the constructor.
mylib::make_shared<T>(); //Annoying!
I could also have the user manually remove their objects:
mylib::unregister<T>(); //Equally annoying!
My goal is to be able to lazily add objects without any prior-registration.
In a grand summary, I want to detect when the object is deleted, and know when to remove its counterpart from the std::map.
Any suggestions?
P.S. Should I even worry about leaving the user data in the map? What are the chances that an object is allocated with the same address as a previously deleted object? (It would end up receiving the same user data as far as my lib is concerned.)
EDIT: I don't think I expressed my problem very well initially. Rewritten.
From you code example, it looks like the external interface is
template <typename T>
registerObject<T>(const std::shared_ptr<T> & _object);
I assume there is a get-style API somewhere. Let's call this getRegisteredData. (It could be internal.)
Within the confines of the question, I'd use std::weak_ptr<void> instead of void*, as std::weak_ptr<T> can tell when there are no more "strong references" to the object around, but won't prevent the object from being deleted by maintaining a reference.
std::map<std::weak_ptr<void>, MyUserData> myMap;
template <typename T>
registerObject<T>(const std::shared_ptr<T> & _object)
{
static inc = 0;
Internal_RemoveDeadObjects();
myMap[std::weak_ptr<void>(_object)].someNum = inc++;
}
template <typename T>
MyUserData getRegisteredData(const std::shared_ptr<T> & _object)
{
Internal_RemoveDeadObjects();
return myMap[std::weak_ptr<void>(_object)];
}
void Internal_RemoveDeadObjects()
{
auto iter = myMap.cbegin();
while (iter != myMap.cend())
{
auto& weakPtr = (*iter).first;
const bool needsRemoval = !(weakPtr.expired());
if (needsRemoval)
{
auto itemToRemove = iter;
++iter;
myMap.erase(itemToRemove);
}
else
{
++iter;
}
}
}
Basically, std::weak_ptr and std::shared_ptr collaborate and std::weak_ptr can detect when there are no more std::shared_ptr references to the object in question. Once that is the case, we can remove the ancillary data from myMap. I'm using the two interfaces to myMap, your registerObject and my getRegisteredData as convenient places to call Internal_RemoveDeadObjects to perform the clean up.
Yes, this walks the entirety of myMap every time a new object is registered or the registered data is requested. Modify as you see fit or try a different design.
You ask "Should I even worry about leaving the user data in the map? What are the chances that an object is allocated with the same address as a previously deleted object?" In my experience, decidedly non-zero, so don't do this. :-)
I'd add a deregister method, and make the user deregister their objects. With the interface as given, where you're stripping the type away, I can't see a way to check for the ref-count, and C++ doesn't provide a way to check whether memory has been deleted or not.
I thought about it for a while and this is as far as I got:
#include <memory>
#include <map>
#include <iostream>
#include <cassert>
using namespace std;
struct MyUserData
{
int someNum;
};
map<void *, MyUserData> myMap;
template<class T>
class my_shared_ptr : public shared_ptr<T>
{
public:
my_shared_ptr() { }
my_shared_ptr(const shared_ptr<T>& s) : shared_ptr<T>(s) { }
my_shared_ptr(T* t) : shared_ptr<T>(t) { }
~my_shared_ptr()
{
if (unique())
{
myMap.erase(get());
}
}
};
template <typename T>
void registerObject(const my_shared_ptr<T> & _object)
{
static int inc = 0;
myMap[(void *)_object.get()].someNum = inc++;
}
struct MyObject
{
int asdf;
};
int main()
{
{
my_shared_ptr<MyObject> obj2;
{
my_shared_ptr<MyObject> obj = make_shared<MyObject>();
obj->asdf = 5;
registerObject(obj);
obj2 = obj;
assert(myMap.size() == 1);
}
/* obj is destroyed, but obj2 still points to the data */
assert(myMap.size() == 1);
}
/* obj2 is destroyed, nobody points to the data */
assert(myMap.size() == 0);
}
Note however that it wouldn't work if you wrote obj = nullptr; , or obj.reset(), since the object isn't destroyed in those cases (no destructor called). Also, you can't use auto with this solution.
Also, be careful not to call (void *)&_object.get() like you were doing. If I'm not terribly wrong, by that statement you're actually taking the address of the temporary that _object.get() returns, and casting it to void. That address, however, becomes invalid instantly after.
This sounds like a job for... boost::intrusive (http://www.boost.org/doc/libs/1_53_0/doc/html/intrusive.html)! I don't think the current interface will work exactly as it stands though. I'll try to work out a few more details a little later as I get a chance.
You can just do
map.erase(map.find(obj));
delete obj;
obj = 0;
this will call the destructor for your user data and remove it from the map.
Or you could make your own manager:
class Pointer;
extern std::map<Pointer,UserData> data;
class Pointer
{
private:
void * pointer;
public:
//operator ()
void * operator()()
{
return pointer;
}
//operator =
Pointer& operator= (void * ptr)
{
if(ptr == 0)
{
data.erase(data.find(pointer));
pointer = 0;
}
else
pointer = ptr;
return *this;
}
Pointer(void * ptr)
{
pointer = ptr;
}
Pointer()
{
pointer = 0;
}
~Pointer(){}
};
struct UserData
{
static int whatever;
UserData(){}
};
std::map<Pointer,UserData> data;
int main()
{
data[Pointer(new UserData())].whatever++;
data[Pointer(new UserData())].whatever++;
data[Pointer(new UserData())].whatever++;
data[Pointer(new UserData())].whatever++;
Pointer x(new UserData());
data[x].whatever;
x = 0;
return 0;
}
I should get the same in both lines..
what happen I get two different values.. like it was aiming to different positions..
I think the error is inside the d->add(*b)
the output is
thiago 14333804
Ph¿├┌ 2816532
to describe it better I put the code below
I got a program
int main(int argc, char **argv) {
CClass* c = new CClass();
BClass* b = c->getNext();
printf("%s %d \n", b->getValue(), b->getValue());
DClass* d = new DClass();
d->add(*b);
printf("%s %d \n", d->getNext(), d->getNext());
cin.get();
return 0;
}
the interfaces are below
class BClass
{
private:
char* value;
bool stale;
public:
BClass(char* value);
~BClass(void);
char* getValue();
bool isStale();
};
class CClass
{
private:
vector<BClass*> list;
public:
CClass(void);
~CClass(void);
BClass* getNext();
};
class DClass
{
private:
vector<BClass*> list;
static bool isStale(BClass* b) { return b->isStale();};
public:
DClass(void);
~DClass(void);
void add(BClass s);
char* getNext();
};
and the implementation follows
//BClass
BClass::BClass(char* value)
{
this->value = value;
this->stale = false;
}
BClass::~BClass(void)
{
}
char* BClass::getValue()
{
return value;
}
bool BClass::isStale()
{
return stale;
}
//CClass
CClass::CClass(void)
{
list.push_back(new BClass("thiago"));
list.push_back(new BClass("bruno"));
list.push_back(new BClass("carlos"));
}
CClass::~CClass(void)
{
}
BClass* CClass::getNext()
{
return list.at(0);
}
//DClass
DClass::DClass(void)
{
}
DClass::~DClass(void)
{
}
void DClass::add( BClass s )
{
list.push_back(&s);
}
char* DClass::getNext()
{
BClass* b = list.at(0);
return b->getValue();
}
When you pass in an instance of class B into D::add() function you create a deep copy of the object and that copy is what is put on stack. Later on you use the address of that copy to push it into list. Once the function is done this automatic variable goes out of scope thus the pointer you used to put into list is no longer valid.
To fix change your interface to avoid deep copies as follows:
void DClass::add( BClass * s )
{
list.push_back(s);
}
Step-by-step of what your code is doing
BClass* b = c->getNext(); // you get the address of the first element from the list (created in constructor) and assign it to b
d->add(*b); // the *b will dereference the object pointed to by b and put it onto stack in preparation to the call to add()
void DClass::add( BClass s ){ // the deep copy of a dereferenced object is put into this function's stack frame
list.push_back(&s); // an address of that temporary copy of the original object is being used to be added to your list
} // this is where the fun happens - once the function is done it will unwind the stack back up and the memory, previously occupied by that temp copy, will be re-used for other purposes. In your case - it will be used to pass parameters to functions d->getNext() (there's always a hidden this parameter to non-static member functions) and later to the printf() function. Remember - your previous pointer to that temp copy is still pointing to the stack, but it's now occupied by different data, causing you to see corruption
General rule of thumb - never use pointers to temp objects ;-)
in the DClass::add function, BClass s is a local variable.
void DClass::add( BClass s )
{
list.push_back(&s);
}
When you call d->add(*b);, you're passing a BClass by value, meaning you're creating a copy of it, and the address of that copy is not the same address of the original.
s will go out of scope as soon as the function returns, and the pointer to it will be invalid. So storing that pointer is no good to you, since dereferencing it would be undefined behaviour.