Cite to Qt document, I know that:
QList will allocate its items on the heap unless sizeof(T) <=
sizeof(void*) and T has been declared to be either a Q_MOVABLE_TYPE or
a Q_PRIMITIVE_TYPE using Q_DECLARE_TYPEINFO.
Would you please explain how it handles the pointers? Is there any difference between Qlist<SomeClass *> and Qvector<SomeClass *>
QList doesn't handle pointers at all.
To QList it's just another value type.
Since the size of a raw pointer is by definition == sizeof(void*), its internal memory layout will be similar to that of QVector.
Related
Isn't a unique_ptr essentially the same as a direct instance of the object? I mean, there are a few differences with dynamic inheritance, and performance, but is that all unique_ptr does?
Consider this code to see what I mean. Isn't this:
#include <iostream>
#include <memory>
using namespace std;
void print(int a) {
cout << a << "\n";
}
int main()
{
unique_ptr<int> a(new int);
print(*a);
return 0;
}
Almost exactly the same as this:
#include <iostream>
#include <memory>
using namespace std;
void print(int a) {
cout << a << "\n";
}
int main()
{
int a;
print(a);
return 0;
}
Or am I misunderstanding what unique_ptr should be used for?
In addition to cases mentioned by Chris Pitman, one more case you will want to use std::unique_ptr is if you instantiate sufficiently large objects, then it makes sense to do it in the heap, rather than on a stack. The stack size is not unlimited and sooner or later you might run into stack overflow. That is where std::unique_ptr would be useful.
The purpose of std::unique_ptr is to provide automatic and exception-safe deallocation of dynamically allocated memory (unlike a raw pointer that must be explicitly deleted in order to be freed and that is easy to inadvertently not get freed in the case of interleaved exceptions).
Your question, though, is more about the value of pointers in general than about std::unique_ptr specifically. For simple builtin types like int, there generally is very little reason to use a pointer rather than simply passing or storing the object by value. However, there are three cases where pointers are necessary or useful:
Representing a separate "not set" or "invalid" value.
Allowing modification.
Allowing for different polymorphic runtime types.
Invalid or not set
A pointer supports an additional nullptr value indicating that the pointer has not been set. For example, if you want to support all values of a given type (e.g. the entire range of integers) but also represent the notion that the user never input a value in the interface, that would be a case for using a std::unique_ptr<int>, because you could get whether the pointer is null or not as a way of indicating whether it was set (without having to throw away a valid value of integer just to use that specific value as an invalid, "sentinel" value denoting that it wasn't set).
Allowing modification
This can also be accomplished with references rather than pointers, but pointers are one way of doing this. If you use a regular value, then you are dealing with a copy of the original, and any modifications only affect that copy. If you use a pointer or a reference, you can make your modifications seen to the owner of the original instance. With a unique pointer, you can additionally be assured that no one else has a copy, so it is safe to modify without locking.
Polymorphic types
This can likewise be done with references, not just with pointers, but there are cases where due to semantics of ownership or allocation, you would want to use a pointer to do this... When it comes to user-defined types, it is possible to create a hierarchical "inheritance" relationship. If you want your code to operate on all variations of a given type, then you would need to use a pointer or reference to the base type. A common reason to use std::unique_ptr<> for something like this would be if the object is constructed through a factory where the class you are defining maintains ownership of the constructed object. For example:
class Airline {
public:
Airline(const AirplaneFactory& factory);
// ...
private:
// ...
void AddAirplaneToInventory();
// Can create many different type of airplanes, such as
// a Boeing747 or an Airbus320
const AirplaneFactory& airplane_factory_;
std::vector<std::unique_ptr<Airplane>> airplanes_;
};
// ...
void Airline::AddAirplaneToInventory() {
airplanes_.push_back(airplane_factory_.Create());
}
As you mentioned, virtual classes are one use case. Beyond that, here are two others:
Optional instances of objects. My class may delay instantiating an instance of the object. To do so, I need to use memory allocation but still want the benefits of RAII.
Integrating with C libraries or other libraries that love returning naked pointers. For example, OpenSSL returns pointers from many (poorly documented) methods, some of which you need to cleanup. Having a non-copyable pointer container is perfect for this case, since I can protect it as soon as it is returned.
A unique_ptr functions the same as a normal pointer except that you do not have to remember to free it (in fact it is simply a wrapper around a pointer). After you allocate the memory, you do not have to afterwards call delete on the pointer since the destructor on unique_ptr takes care of this for you.
Two things come to my mind:
You can use it as a generic exception-safe RAII wrapper. Any resource that has a "close" function can be wrapped with unique_ptr easily by using a custom deleter.
There are also times you might have to move a pointer around without knowing its lifetime explicitly. If the only constraint you know is uniqueness, then unique_ptr is an easy solution. You could almost always do manual memory management also in that case, but it is not automatically exception safe and you could forget to delete. Or the position you have to delete in your code could change. The unique_ptr solution could easily be more maintainable.
I've written a struct called Node, and want to be able to use pointers to that struct as entries in a Phobos BinaryHeap. However, I am not sure how opEquals and opCmp are implemented for pointers to structs (or in fact, in general). I've not been able to find anything in the documentation to help me. Could anyone point me in the right direction?
If you have an array of these Node* you can do something like that:
Node*[] arr = ....;
auto heap = heapify!(yourCustomCompareFuncGoesHere)(arr);
If you can't use heapify for whatever reason you can create a BinaryHeap by:
BinaryHeap!(Node*[], yourCustomCompareFuncGoesHere) heap;
yourCustomCompareFuncGoesHere will be passed as an alias template parameter to the heap and used for the "is less comparison" for sorting. Compare to the struct signature of BinaryHeap in the phobos docs.
Is it possible to use QPointer with QHash?
QPointer<QHash<QString, QPointer<QStringList>> > pHash;
QPointer can only be used with QObject subclasses. Thus it cannot be used with QHash or QStringList, as both aren't QObject's. If the code above compiles for you, that's probably because you don't use pHash yet? Even initializing such a QPointer, e.g.
QPointer<QHash<QString, QString> > foo( new QHash<QString, QString>() );
gives errors like the following one (gcc):
error: cannot convert ‘QHash<QString, QString>*’ to ‘QObject*’ in initialization
If you really need (smart) pointers to containers, try QSharedPointer, which doesn't require the contained object to be of any specific type.
Usually one creates containers on the stack though, creating them on the heap is unidiomatic and unnecessary in almost all cases. Qt's containers are implicitly shared, thus copying them is cheap.
Let's say I allocate memory to a pointer to a structure:
CatStructure * cat; // assume a CatStructure has name and weight
Let's say I initialize cat to:
cat->name = "pippy";
cat->weight = 100;
If I save a reference to cat->name and cat->weight, do I still need to save a reference to cat? In other words, is it necessary to save a reference to a pointer to a structure if I've already saved references to its members?
CatStructure *cat; does not allocate memory for the given struct, it just gives you a place to store a reference to a pointer. We'll say that you know this, and that you're newing correctly to actually allocate memory.
Every new must be matched with a corresponding call to delete or you will leak memory. Technically if you're saving a reference to one of the members correctly you could do some pointer math to recover the reference to the struct, but that's unnecessarily obtuse. Just save the pointer so you can clean it up later.
if you delete the structure, any references to its pointers or members will no longer be valid. those invalid pointers/references are called 'dangling'.
Hopefully this isn't too stupid but I want to make sure I'm doing this right.
Some Qt functions return Qt objects as values, but we may want to store them in a pointer somewhere. For example, in QDomDocument, the function documentElement returns a QDomElement, not a pointer to it. Now, as a member of my class I have:
QDomElement *listRootElement;
In a function that sets things up I am using this:
listRootElement = new QDomElement;
*listRootElement = mainIndex->documentElement();
(mainIndex is a QDomDocument.)
This seems to work, but I just want to make sure I'm doing it right and that nothing will come back to bite me.
It would be very similar for some of the image functions where a QPixmap might be returned, and I want to maintain pointers to QPixMap's.
Thanks for any comments!
Assuming that you want to store a pointer to a QDomElement for some reason, and assuming that you aware of the potential pitfalls with pointers (like, two pointers might point to the same object):
The only thing to keep in mind is that the popular 'parent takes care of deleting children' system which Qt uses is only available for QObject (sub-)classes. So when new'ing a QString or a QDomElement or something like that, keep in mind that you do have to delete it yourself, too.
I'm guessing, but I think this:
listRootElement = new QDomElement(mainIndex->documentElement());
...may allow the compiler to optimise better (see this question for some reasoning).
You're overwriting the initially allocated object:
QDomElement *listRootElement; // undefined ptr value, I'd prefer null or new right away
listRootElement = new QDomElement;
*listRootElement = mainIndex->documentElement();
You're essentially doing:
int *x = new int(42);
*x = 47;
This works because both QDomElement and int implements the assignment operator (=).
Note that there's no need to delete anything, as the returned temporary is copied into your newly allocated object.