I have some legacy code where a Object is dynamically allocated and then emitted:
QList<MyClass *> *list = new QList<MyClass *>();
...
emit listReady(*row);
void OtherClass::slotList(QList<MyClass> list) {
...
delete list???
}
i can delete the objects in the list and i can clear the List, is it possible to delete the list itsef in my slot?
is it possible to delete the list itsef in my slot?
No, it's not possible. Because your slot accept the list by value, which is copy of original QList<MyClass *> *list object.
void OtherClass::slotList(QList<MyClass> list)
To be able delete the list object you should change the slotList arguments to accept the pointer to list.
Not in the way you wrote it. list the parameter is passed by value, so it's a copy of the list to which the pointer list points (it might help clarity of your question if you gave the two variables distinct names).
Even if you changed slotList to take its parameter by reference (slotList(QList<MyClass> &list)), it would still not be a good idea to delete &list inside. That's because it Qt, some signal-slot connections (such as queued connections or connections across threads) do not operate directly on the signal's parameters, but on their copies.
If, for some reason, you need to propagate ownership of the list from the creator signal to the slot and delete it there, you must change the slot to accept a pointer instead:
QList<MyClass *> *row = new QList<MyClass *>();
...
emit listReady(row);
void OtherClass::slotList(QList<MyClass> *list) {
...
delete list;
}
However, the most important question is: why are you actually allocating the QList dynamically in the first place? Containers (like QList) very rarely require dynamic allocation. That holds even more for Qt containers which are implemented with implicit sharing and copy-on-write, so even copying a QList is cheap (it does not copy its contents). The correct solution for you is therefore most likely to have row be an object instead of a pointer, and forget the entire new/delete business.
No, it's not possible, as list is not (the same) pointer nor reference to *list (in which case you could delete &list; (yes, a dirty hack) - only in case of direct connection) and is passed by value instead.
Why are you dynamically allocating the list in the first place?
Related
Why can't I call append on this QList?
QList<Artist> * DataManagement::create_and_get_artists(){
QList<Artist> *artists = new QList<Artist>;
for(int i; i < m_allSongs->rowCount(); i++){
Artist *artist = new Artist();
artist->setName(m_allSongs->record(i).value("artistName").toString());
artists->append(artist);
}
return artists;
}
Screenshot of error
Error message: "no matching member function for call to 'append'".
You can call append on a QList type, but only with an appropriate parameter.
In the code, artist is a pointer to the Artist type, while the QList is a list of Artist types.
In the screenshot, no parameter is given at all.
Let's look at the documentation (always check the documentation first!).
There are two overloads of append():
void QList::append(const T &value)
and
void QList::append(const QList<T> &value)
So you can append a value or a list of values.
In your code on the screenshot, you call artists->append();.
That is, you are not providing any argument. No member function append() with zero arguments exist.
Managing Object Lifetimes
Remember that you are responsible for managing memory in C++!
You have a QList<Artist>, i.e., a list of actual objects. Yet you create an Artist using new. Now you have a pointer to a heap allocated object.
Calling append(obj) will actually copy the object, i.e., call the copy constructor! You are then responsible to free the temporary object you created!
Alternatively, you could use a QList<Artist*>, i.e., a list of pointers. But I think this is the worst option.
You could also construct a temporary object on the stack and then copy it:
Artist artist{};
artist.setName("bla");
artists->append(artist);
But it would be much better - if you use Qt6 - to just construct the object directly into the list, using emplaceBack().
(You need the matching constructor, of course).
I have an object A, that I want to wrap with a list of objects (pointers to objects) of type B, that A should process.
The problem is, that some of B objects can be deleted and A doesn't know about it. I know I can handle it with exceptions, but I would rather to avoid it.
Full problem: I'm writing C++ SFML project, I want to wrap a sf::RenderWindow with a vector of sf::Drawable * pointers to objects, that window should draw. And problem is the same. Some of sf::Drawable objects may be already deleted, but sf::RenderWindow tries to use it.
I can possibly cancel the idea of wrapping, but if there a good design solution, it would be great.
You can use a std::unique_ptr which will return true or false in an if() statement depending if it has been deleted or not:
// use a std::unique_ptr that will record if its target has been deleted
std::vector<std::unique_ptr<sf::Drawable>> drawables;
// deleting an element
for(auto& drawable: drawables)
{
if(needs_to_be_deleted(drawable.get()))
drawable.reset(); // deletes object
}
// process elements
for(auto& drawable: drawables)
{
if(drawable) // returns false if element is deleted
{
// pass by reference or pointer (using get())
do_something_with_drawable(drawable.get());
}
}
You have to ensure memory is not reused, as it will result in undefined behavior if the object is no longer live when you use it.
Create a map for the live objects, and only use value, if it is still in the map
I have a class with an array of pointers that gets dynamically allocated in the constructor. This class also has a function to populate the array.
HolderClass::HolderClass(int number)
{
arrayOfPointers = new ItemClass*[number];
}
HolderClass::addItem(int number, ItemClass item)
{
arrayofPointers[number] = &item;
}
Even though this would compile is my understanding correct in that I would actually be populating the array with dangling pointers since the lifetime of the item variable is only for the duration of the addItem function?
What would be the correct way of populating the arrayOfPointers with pointers to the passed in items? The one complexity here is that there will be child classes of ItemClass that will get passed to the addItem function so I don't believe default copy constructors could be used.
EDIT: This code is for an Arduino so I'm fairly limited in what can and can't be done. This also means that I would like to keep things simply for users of this class (since there are lots of Arduino newbies) and not require them to pass in a pointer to the addItem function (which would require them to manage the life of the passed in ItemClass object).
What would be the correct way of populating the arrayOfPointers with pointers to the passed in items?
Firstly, don't use raw new and delete. Use containers and smart pointers.
struct HolderClass
{
std::unique_ptr<std::unique_ptr<ItemClass>[]> arrayOfPointers;
// ...
};
HolderClass::HolderClass(int number)
{
arrayOfPointers = std::make_unique<std::unique_ptr<ItemClass>[]>(number);
}
Then, pass a pointer to addItem instead of a value to avoid object slicing and lifetime issues:
HolderClass::addItem(int number, std::unique_ptr<ItemClass> item)
{
arrayofPointers[number] = std::move(item);
}
I am working on a project for my University where i have to implement a Hash table. I am quite new to c++, so please forgive me if I am not specific enough or if I have completely wrong assumptions.
Soo..my main problem is that I have a so called "Bucket" which is a struct in my program and which contains a pointer array of N(template parameter) places.
struct Bucket {
T *kptr{ nullptr };
Bucket *bptr{ nullptr }; //For overflow chains (linear Hashing)
Bucket(Bucket *bptr = nullptr) : kptr(new value_type[N]),bptr(bptr) {}
~Bucket() { if(bptr) delete[] bptr; if (kptr) delete[] kptr; }
};
In my main Class named My_Set for example I have an additional Bucket *table of [1<
My first assumption was to initialize the kptr array to nullptr and then in the insert method to make something like
void insert(Bucket &bkt, T &key) {
for (int i=0; i<N, ++i) {
if (bkt.kptr[i]) { //Check on nullptr!
kptr[i] = key;
}
}
}
But that´s not possible because then kptr should be Bucket T **kptr and not Bucket *kptr as far as i understood it.
So, is there any other efficient way to check one single field of an array if it has been assigned to an Object already or not?
IMPORTANT: I am not allowed to use STL Containers, Smart Poitners and similar things which would make the whole thing much easier.
Thanks!
Check whether pointer in pointer array is already “filled”
... So, is there any other efficient way to check one single field of an array if it has been assigned to an Object already or not?
Yes: Initialize the pointer to nullptr. Then, if the pointer has a value other than nullptr, you know that it has been pointed to an object.
However, your professor is correct that your checking is inefficient. On every insert you iterate through all previously inserted objects.
That is unnecessary. You can avoid trying to check whether any of the pointers have been assigned by remembering where the next free pointer is. How can we "remember" things in algorithms? Answer: Using variables. Since you must remember for each instance of your container, you need a member variable.
Since you are using this new variable to remember the next free pointer, how about we name it next_free. Now, considering that the variable must refer to an existing object, what type should it have? A reference would be a good guess, but you must also be able to reassign it once an element is inserted. What can refer to an object like a reference, but can be reassigned? Answer: A pointer. Since this pointer is going to point to a pointer to T, what should be its type? Answer: T**. What should it be initialized to? Answer: The address of the first element of kptr. With such member, insert can be implemented like this:
void insert(T &key) { // why would there be a Bucket argument for insert?
*next_free++ = new T(key); // Note: Do not do this in actual programs. Use
// RAII containers from the standard library instead
}
then kptr should be Bucket T **kptr and not Bucket *kptr as far as i understood it.
Correct. A T* can not point to an array that contains pointers (unless T happens to be a pointer) - it can point to an array of T objects. A T** can point to an array of pointers to T.
Instead of pointers to separately allocated objects, it would be more efficient to use a flat resizable array. But since you are not allowed to use std::vector, you would then have another standard container to re-implement. So consider whether the efficiency is worth the extra work.
I need a collection in which i can store heap-allocated objects having virtual functions.
I known about boost::shared_ptr, std::unique_ptr (C++11) and boost::ptr_(vector|list|map), but they doesn't solve duplicate pointer problem.
Just to describe a problem - i have a function which accepts heap-allocated pointer and stores it for future use:
void SomeClass::add(T* ptr)
{
_list.push_back(ptr);
}
But if i call add twice with same parameter ptr - _list will contain two pointers to same object and when _list is destructed multiple deletion of same object will occur.
If _list will count pointer which he stores and uses them at deletion time then this problem will be solved and objects will not be deleted multiple times.
So the question is:
Does somebody knows some library with collections (vector,list,map in essence) of pointer with auto-delete on destruction and support of reference counting?
Or maybe i can solve this problem using some other technique?
Update:
I need support of duplicate pointers. So i can't use std::set.
As Kerrek SB and Grizzly mentioned - it is a bad idea to use raw pointers in general and suggests to use std::make_shared and forget about instantiation via new. But this is responsibility of client-side code - not the class which i designs. Even if i change add signature (and _list container of course) to
void SomeClass::add(std::shared_ptr<T> ptr)
{
_list.push_back(ptr);
}
then somebody (who doesn't know about std::make_shared) still can write this:
SomeClass instance;
T* ptr = new T();
instance.add(ptr);
instance.add(ptr);
So this is not a full solution which i wait, but useful if you write code alone.
Update 2:
As an alternative solution i found a clonning (using generated copy constructor). I mean that i can change my add function like this:
template <typename R>
void SomeClass::add(const R& ref)
{
_list.push_back(new R(ref));
}
this will allow virtual method (R - class which extends some base class (interface)) calls and disallow duplicate pointers. But this solution has an overhead for clone.
Yes: std::list<std::shared_ptr<T>>.
The shared pointer is avaiable from <memory>, or on older platforms from <tr1/memory>, or from Boost's <boost/shared_ptr.hpp>. You won't need to delete anything manually, as the shared pointer takes care of this itself. You will however need to keep all your heap pointers inside a shared pointer right from the start:
std::shared_ptr<T> p(new T); // legacy
auto p = std::make_shared<T>(); // better
If you another shared pointer to the same object, make a copy of the shared pointer (rather than construct a new shared pointer from the underlying raw pointer): auto q = p;
The moral here is: If you're using naked pointers, something is wrong.
Realize that smart pointers are compared by comparing the underlying container. So you can just use a std::set of whatever smartpointer you prefer. Personally I use std::unique_ptr over shared_ptr, whenever I can get away with it, since it makes the ownership much clearer (whoever holds the unique_ptris the owner) and has much lower overhead too. I have found that this is enough for almost all my code. The code would look something like the following:
std::set<std::unique_ptr<T> > _list;
void SomeClass::add(T* ptr)
{
std::unique_ptr<T> p(ptr);
auto iter = _list.find(p);
if(iter == _list.end())
_list.insert(std::move(p));
else
p.release();
}
I'm not sure right now if that is overkill (have to check if insert is guaranteed not to do anything, if the insertion fails), but it should work. Doing this with shared_ptr<T> would look similar, although be a bit more complex, due to the lack of a relase member. In that case I would probably first construct a shared_ptr<T> with a do nothing deleter too pass to the call to find and then another shared_ptr<T> which is actually inserted.
Of course personally I would avoid doing this and always pass around smart pointers when the ownership of a pointer changes hands. Therefore I would rewrite SomeClass::add as void SomeClass::add(std::unique_ptr<T> ptr) or void SomeClass::add(std::shared_ptr<T> ptr) which would pretty much solve the problem of having multiple instances anyways (as long as the pointer is always wrapped).