unique_ptr reset problem
-
I have some problem with unique_ptr.reset(): when i pass a pointer to reset(so unique_ptr take ownership of it) it doesn't reset the source pointer. This cause the pointer to not be unique.
std::unique_ptr<TestClass> ptr; TestClass *testClass= new TestClass ; ptr.reset(testClass); //testClass is still valid, should be nullptr now...
from the <memory> header file
reset()
doesn't set nothing tonullptr
-
so how i can transfer ownership to unique_ptr?? basically what i want to achieve is to avoid to passing unique_ptr around, for example in a tree structure.
-
@ceora already answer you, I would add more details about it.
The responsible of std::unique_ptr is help you manage the life time of the resource(I say resource, not memory because it can handle more than that).
Basically, the api reset will reset the pointer hold by the unique_ptr
Solution 1 :auto test_class = new TestClass; std::unique_ptr<TestClass> ptr(test_class ); //let the unique_ptr handle the resource--test_class ptr.reset(nullptr); //set the resource handle by the unique_ptr to nullptr
Could we initialize the unique_ptr with better solution?Yes
Solution 2 :std::unique_ptr<TestClass> ptr(new TestClass);
Is it possible to make it even better?Yes
Solution 3 :auto ptr = std::make_unique<TestClass>(); //need c++14
If you cannot wait until most of the compiler to support c++14, you can implement it by yourself
template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); }
What are the benefits of using make_unique?
1 : it makes your codes more compact
2 : it helps you avoid the trap of "resource leak"suppose you have an api which accept std::unique_ptr<TestClass> as following
void do_something(std::unique_ptr<TestClass> lhs, std::unique_ptr<TestClass> rhs) { //......... }
If you call it like this
do_something(std::unique_ptr<TestClass>(new TestClass), std::unique_ptr<TestClass>(new TestClass));
The memory may leak if one of the construction fail(for details, please study effective c++ or effective modern c++)
@If you need to pass that pointer to functions or containers you could use std::shared_ptr
Not really, you can pass by pointer, pass by reference or move it.(1) pass by pointer
void do_something(TestClass *ptr);
(2) pass by reference
void do_something(std::unique_ptr<TestClass> &ptr);
(3) move it
void do_something(std::unique_ptr<TestClass> ptr);
you can move it as following
auto ptr = std::make_unique<TestClass>(); do_something(std::move(ptr));
or
do_something(std::make_unique<TestClass>());
I prefer solution (1) since that api is more flexible(do not bound to particular smart pointer).
Raw pointer is not ideal at resource management but very good at access resourceIn my humble opinion, the objective of std::shared_ptr is sharing the resource
It is much harder to predict the life time of the shared_ptr, and it is also more expensive than
the zero performance penalty unique_ptr.Besides, unique_ptr could show you that this is a unique resource -
@stereomatchingkiss thanks for the explanation! How I can find out when using shared_ptr, unique_ptr or raw pointer, ore better when resource can be considered shared or as visitors (using the pointer, look at the data, ..)? if pointer are mostly used for data sharing(for allocation are better containers), when use unique_ptr instead of non pointer variable? Another problem is debugging smart pointer, they aren't deferenced making them hard to read..
-
@stereomatchingkiss thanks for the explanation! How I can find out when using shared_ptr, unique_ptr or raw pointer, ore better when resource can be considered shared or as visitors (using the pointer, look at the data, ..)? if pointer are mostly used for data sharing(for allocation are better containers), when use unique_ptr instead of non pointer variable? Another problem is debugging smart pointer, they aren't deferenced making them hard to read..
shared_ptr::use_count() helps for knowning if there are other instances sharing this memory.
The debugging of smart pointers may be an issue of the debugger used. The main problem, I see, is that there is an extra layer in between, which makes debugging less intuitive. However, this is the little pain you have to accept with the comfort and advantages of smartpointers. Besides the additional layer there is no other problem in debugging. -
@ceora koahnig already answer your question
How I can find out when using shared_ptr, unique_ptr or raw pointer
Before I answered you this question, I would like to say the best way(maybe) is "do not use any pointer, put your resource on stack".Example:
void MainWindow::closeEvent(QCloseEvent *event) { QSettings setting{"ThamSoftWare", "QRenamer"}; setting.setValue("geometry", saveGeometry()); event->accept(); }
Is easier to deal and more efficient than(because you save the cost of allocate memory on heap)
void MainWindow::closeEvent(QCloseEvent *event) { auto setting = std::make_unique<QSettings>{"ThamSoftWare", "QRenamer"}; setting->setValue("geometry", saveGeometry()); event->accept(); }
If you just need a local object to do some job, rather than new it and put it into smart pointer, just create it on stack(someone call them auto object?).
As far as I know, if you do not need to shared the resource, then you do not need the shared_ptr.You could think it like this way too, if stack work for you, do not use unique_ptr, if unique_ptr works for you, do not use shared_ptr, treat shared_ptr as the last resort.
I never have any real life experience when shared_ptr is a much better solution than scope object on stack or unique_ptr, so the following example may look fake(pseudo codes).
Assuming you are design a game, the game have a monster which could spawn themselves(slime)
Even the slime can spawn, all of the slime share some common state(mp, hp or other's) and some
different states.class slime_state { public: //......some states } class slime { public: //some operations private: std::shared_ptr<slime_state> states_; }
In this kind of situation, you may want to create many slime with same states_ and do not want to bother to delete the slime_state when the last slime die. This maybe a good situation to give shared_ptr a try.
For more details, you can study "The c++ programming language, 4th"
Another problem is debugging smart pointer, they aren't deferenced making them hard to read..
I seldom use the debug mode to debug, so I cannot give you much suggestion about that, sorry -
@ceora koahnig already answer your question
How I can find out when using shared_ptr, unique_ptr or raw pointer
Before I answered you this question, I would like to say the best way(maybe) is "do not use any pointer, put your resource on stack".Example:
void MainWindow::closeEvent(QCloseEvent *event) { QSettings setting{"ThamSoftWare", "QRenamer"}; setting.setValue("geometry", saveGeometry()); event->accept(); }
Is easier to deal and more efficient than(because you save the cost of allocate memory on heap)
void MainWindow::closeEvent(QCloseEvent *event) { auto setting = std::make_unique<QSettings>{"ThamSoftWare", "QRenamer"}; setting->setValue("geometry", saveGeometry()); event->accept(); }
If you just need a local object to do some job, rather than new it and put it into smart pointer, just create it on stack(someone call them auto object?).
As far as I know, if you do not need to shared the resource, then you do not need the shared_ptr.You could think it like this way too, if stack work for you, do not use unique_ptr, if unique_ptr works for you, do not use shared_ptr, treat shared_ptr as the last resort.
I never have any real life experience when shared_ptr is a much better solution than scope object on stack or unique_ptr, so the following example may look fake(pseudo codes).
Assuming you are design a game, the game have a monster which could spawn themselves(slime)
Even the slime can spawn, all of the slime share some common state(mp, hp or other's) and some
different states.class slime_state { public: //......some states } class slime { public: //some operations private: std::shared_ptr<slime_state> states_; }
In this kind of situation, you may want to create many slime with same states_ and do not want to bother to delete the slime_state when the last slime die. This maybe a good situation to give shared_ptr a try.
For more details, you can study "The c++ programming language, 4th"
Another problem is debugging smart pointer, they aren't deferenced making them hard to read..
I seldom use the debug mode to debug, so I cannot give you much suggestion about that, sorry@stereomatchingkiss
shared_ptr are good when have a container holding the shared_ptr, but you need to update while the actual object is still in use.
E.g. you change the properties of an object by placing a new pointer and removing the old one. When the object is still used somewhere, this routine can be completed without side effects. For such reasons I am using shared_ptr very often. In real-time apps the primary owner cannot always wait until the each subs are finished. Otherwise I would have to do all the book-keeping myself.I have never used a unique_ptr so far.
At least on windows through Qt creator with MinGW the debugging has no major disadvantges besides the additional layer. IIRC also under Ubuntu it did work in the same manor.
-
@stereomatchingkiss
shared_ptr are good when have a container holding the shared_ptr, but you need to update while the actual object is still in use.
E.g. you change the properties of an object by placing a new pointer and removing the old one. When the object is still used somewhere, this routine can be completed without side effects. For such reasons I am using shared_ptr very often. In real-time apps the primary owner cannot always wait until the each subs are finished. Otherwise I would have to do all the book-keeping myself.I have never used a unique_ptr so far.
At least on windows through Qt creator with MinGW the debugging has no major disadvantges besides the additional layer. IIRC also under Ubuntu it did work in the same manor.
@koahnig
From what i heard from Herb Sutter conf, it's better to always use unique_ptr if you don't know if resource will be shared, cause shared_ptr are less efficient (because thy keep a reference count), also it's better to don't pass smart pointer around unless you want express the intention to pass ownership. My problem is that i want to optimize code before write it XD. However if i want go for sure i think i will always use shared_ptr too...For the debugging problem, is the additional layer that make hard to read for me, i would like to have data well presented so i can look fast at them, without expand too many tree elements in debug view.
-
@koahnig
From what i heard from Herb Sutter conf, it's better to always use unique_ptr if you don't know if resource will be shared, cause shared_ptr are less efficient (because thy keep a reference count), also it's better to don't pass smart pointer around unless you want express the intention to pass ownership. My problem is that i want to optimize code before write it XD. However if i want go for sure i think i will always use shared_ptr too...For the debugging problem, is the additional layer that make hard to read for me, i would like to have data well presented so i can look fast at them, without expand too many tree elements in debug view.
@ceora
However, that is exactly the place where I am using the shared_ptr. I have a central container holding information which is required by other parts of the SW. The information will change once in a while, but the already started calculations cannot be stopped, but have to be finished with the very same information in all places. Therefore, I could do only an update when all calculations have been done. However, this point I might have to start the next one already. Certainly I could do all this without using a standard shared_ptr, but at day's end I would probably add a similar and more time-consuming functionality.The additional layer is basically and two additonal clicks (IIRC) in the debug window. Makes tghe window a bit bigger, but that's it.
Certainly shared_ptr are not a good solution everywhere. Because of overhead they should be used only where required.