Qt QList - removeAll deallocating memory - c++

I have a QList of MyClass pointers like this:
QList<MyClass*> myList;
When I call myList.removeAll(someObjPtr); it doesn't just remove the pointers from the QList, it calls delete on them internally. Is there a way to get around this or is there an alternative QList method that would just remove the elements without deallocating them?
EDIT: Internals of removeAll:
template <typename T>
Q_OUTOFLINE_TEMPLATE int QList<T>::removeAll(const T &_t)
{
int index = indexOf(_t);
if (index == -1)
return 0;
const T t = _t;
detach();
Node *i = reinterpret_cast<Node *>(p.at(index));
Node *e = reinterpret_cast<Node *>(p.end());
Node *n = i;
node_destruct(i);
while (++i != e) {
if (i->t() == t)
node_destruct(i);
else
*n++ = *i;
}
int removedCount = e - n;
d->end -= removedCount;
return removedCount;
}
As you can see it calls node_destruct, which does this:
template <typename T>
Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *n)
{
if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic) delete reinterpret_cast<T*>(n->v);
else if (QTypeInfo<T>::isComplex) reinterpret_cast<T*>(n)->~T();
}
As you see, there is a delete being called.

QList has nothing to do with Qt 3's QPtrList.
None of the QList methods interpret stored pointers in a special way. You must be testing it wrongly. For example, the code below happily leaks two C instances and never deletes them.
Perhaps you were thinking of qDeleteAll from QtAlgorithms? This one will delete the instances.
Note that QList's implementation may allocate per-item memory to store your instances in, and will free that memory when appropriate. In no case will QList implementation delete a pointer that you store in the list: the only way QList interprets the stored data is via its type, and then it's only to decide whether the items are memory-movable, and whether they fit into a void* or do they need to be individually allocated. In fact, all pointer types are stored in QList as if it were a QVector, with a bit of room added at the beginning and the end to make push_front and push_back have amortized O(1) cost.
#include <QtCore>
struct C {
static int ctr;
C() { ctr ++; }
~C() { ctr --; qDebug() << (void*)this << "C instance destructed"; }
};
int C::ctr;
int main() {
auto c1 = new C, c2 = new C;
auto list1 = QList<C*>() << c1 << c2;
list1.removeAll(c1); // doesn't delete the pointed-to objects
list1.removeAll(c2);
Q_ASSERT(list1.isEmpty());
Q_ASSERT(C::ctr == 2);
// we'll happily leak both instances above
auto list2 = QList<C*>() << new C << new C << new C;
qDeleteAll(list2); // invokes delete on all objects
Q_ASSERT(C::ctr == 2);
}

node_destruct does not delete the objects pointed to by QLists of pointers. If you look closely, it only deletes n->v for large and static types. QList internally allocates large and static types on the heap, so the delete is necessary.
For pointer types, the QTypeInfo<T> specialization is:
template <typename T>
class QTypeInfo<T*>
{
public:
enum {
isPointer = true,
isComplex = false,
isStatic = false,
isLarge = false,
isDummy = false
};
};
As you see, pointers are neither large nor static, so are not deleted

Related

How to use shared_ptr to manage an object placed with placement new?

A fairly common thing I need to do is allot an object and some memory it'd like, in a strictly contagious region of memory together:
class Thing{
static_assert(alignof(Thing) == alignof(uint32), "party's over");
public:
~Thing(){
//// if only, but this would result in the equivalent of `free(danglingPtr)` being called
//// as the second stage of shared_ptr calling `delete this->get()`, which can't be skipped I believe?
// delete [] (char*)this;
}
static Thing * create(uint32 count) {
uint32 size = sizeof(Thing) + sizeof(uint32) * count; // no alignment concerns
char * data = new char[size];
return new (data)Thing(count);
}
static void destroy(Thing *& p) {
delete [] (char*)p;
p = NULL;
}
uint32 & operator[](uint32 index) {
assert(index < m_count);
return ((uint32*)((char*)(this + sizeof(Thing))))[index];
}
private:
Thing(uint32 count) : m_count(count) {};
uint32 m_count;
};
int main(){
{
auto p = shared_ptr<Thing>(Thing::create(1));
// how can I tell p how to kill the Thing?
}
return 0;
}
In Thing::Create() this is done with placement new into a section of memory.
I'd also like to have a shared pointer manage it in this case, using auto p = shared_ptr<Thing>(Thing::create(1)). But If it calls the equivalent of delete p.get() when the ref count empties, that'd be undefined as it mismatches the type and, more importantly, mismatches plural new with singular delete. I need it to delete in a special way.
Is there a way to easily set that up without defining an outside function? Perhaps by having the shared pointer call Thing::destroy() when the ref count empties? I know that shared pointer can accept a "deleter" as a template argument, but I'm unsure how to use it, or if it's even the proper way to address this?
std::shared_ptr accepts a deleter function as a second parameter, so you can use that to define how the managed object will be destroyed.
Here's a simplified example:
class Thing
{
public:
~Thing()
{
std::cout << "~Thing\n";
}
static std::shared_ptr<Thing> create() {
char * data = new char[sizeof(Thing)];
Thing* thing = new (data) Thing{};
return std::shared_ptr<Thing>{thing, &Thing::destroy};
}
static void destroy(Thing* p) {
p->~Thing();
delete [] (char*)p;
}
};
int main()
{
auto p = Thing::create();
}
Live Demo

Array of Pointers to an Abstract Class: to nullptr or not to nullptr (C++)

I want to loop through an array of pointers to an abstract class to find an "empty" slot, that is to check whether an element points to an object of a derived class or not. My approach is to create the array and set each element to nullptr. Then, I can check if the element is nullptr.
This works, but is there a better way?
Edit: Can I check for the first "empty" element in the array of pointers to an abstract class (in which derived classes will periodically be constructed and pointed to by the array, rendering that element not "empty"), without assigning each element to nullptr upon setting up the array and then checking for nullptr as a way to check if the element is "empty"? In other words, can I directly check whether the element points to a constructed base class or not?
Cat** catArray = new Cat*[200];
for(int i = 0; i < 200; i++){
catArray[i] = nullptr;
}
for(int i = 0; i < 200; i++){
if(catArray[i] == nullptr){ //edited, was typo as "!="
AddRealCat(...);
break;
}
}
I wonder if there's an easier way to do this, to check whether an element in an array of pointers to an abstract class points to an object of a derived class or is just an abstract pointer, without setting the element to nullptr. Like, is there a bool IsObject(ObjectType* ptr) or something in the standard library?
And, I wonder if setting each element to nullptr poses any potential problems, other than the computing cost of looping through the array and setting the elements to nullptr.
You would have to use dynamic_cast to cast a base class pointer to a derived class pointer. dynamic_cast performs type safe down casting.
If the result of dynamic_cast is not nullptr then the cast has been successful. Otherwise no derived class pointer can be obtained from the pointer.
You would have to do like this:
Cat *pCat = dynamic_cast<Cat*>(catArray[i]);
if (pCat)
{
AddRealCat(...);
break;
}
where catArray is an array of base class pointers.
Update
I think there's an error with creating an array of real cat objects:
for(int i = 0; i < 200; i++){
if(catArray[i] != nullptr){
AddRealCat(...);
break;
}
}
Surely you need to check == nullptr since you initialising all array elements to nullptr? I think you need to make the following change:
for(int i = 0; i < 200; i++){
if(catArray[i] == nullptr){
catArray[i] = new RealCat();
break;
}
}
I guess the real easier way to do that other using dynamic_cast is using std::vector instead of a raw pointer.
Sample code
#include <string>
#include <iostream>
#include <vector>
struct Cat{
virtual ~Cat() = default;
virtual void meow() const = 0;
};
struct Meow : Cat{
void meow() const override{ std::cout << "meow" << std::endl; }
};
int main()
{
std::vector<Cat*> vec{100};
vec[1] = new Meow();
for(auto c : vec){
if(auto m = dynamic_cast<Meow*>(c)){
m->meow();
}
}
// don't forget to release memory
for(auto c : vec){
delete c;
}
}
Live Example
Modern version, using smart pointers.
#include <string>
#include <iostream>
#include <vector>
#include <memory>
struct Cat{
virtual ~Cat() = default;
virtual void meow() const = 0;
};
struct Meow : Cat{
void meow() const override{ std::cout << "meow" << std::endl; }
};
int main()
{
std::vector<std::unique_ptr<Cat>> vec{100};
vec[1] = std::make_unique<Meow>();
for(auto&& c : vec){
if(auto m = dynamic_cast<Meow*>(c.get())){
m->meow();
}
}
// you don't need to manually clear the memory.
}
Live Example

Set a sharing pointer to NULL

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).

Knowing when to delete associated user data from a std::map<void *, ...>

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;
}

Generic class for dynamic arrays in c++

Is it possible to make a generic class that acts as a dynamic array of objects of any type?
I want a class that basically does this:
MyObj * obj1 = new MyObj();
MutableArray * arr = new MutableArray();
arr->addObject(obj1);
MyObj * obj2 = arr->objectAtIndex(0);
// obj1 and obj2 now points to the same object
This is what the code would look like. I know this doesn't work, but you get the idea.
What I need is some generic type for an object. The array itself just consists of pointers so the size of the object shouldn't matter, right?
So, is this possible?
.h-file
class MutableArray
{
private:
class * objs;
int length;
int capacity;
public:
MutableArray();
void add(class * obj);
class objectAtIndex(int index);
};
cpp-file
MutableArray::MutableArray()
{
length = 0;
capacity = 0;
}
void MutableArray::add(class * obj)
{
if(length >= capacity)
{
this->enlarge();
}
objs[length] = obj;
length++;
}
void MutableArray::enlarge()
{
int newCapacity = (capacity * 2)+1;
class * newObjs = new class[newCapacity]
if(capacity != 0)
{
delete [] objs;
}
objs = newObjs;
capacity = newCapacity;
}
class MutableArray::objectAtIndex(int index)
{
return objs[index];
}
This has already been invented and is called std::vector<>.
Is it possible to make a generic class that acts as a dynamic array of objects of any type?
For the dynamic array use std::vector, for objects of any type use boost::any.
std::vector< boost::any > anything;
You want to use STL std::vector.
Yes. It actually exists and is called std::vector.