This question already has answers here:
How to "return an object" in C++?
(8 answers)
Closed 8 years ago.
I am new to C++ and I'm stuck at the following problem:
Imagine you have a function that creates a new object and returns this object. What is the best approach to do that?
I have found 3 different solutions.
Solution 1 Using the copy constructor
MyClass getMyClass() {
MyClass obj;
//work with obj, set values...
return obj;
}
As far as I understod it, you create a new object, copy that object, destroy the first and return the copied object. So I created two object, but I only needed one. Is that right?
Solution 2 Creat the object on the heap and use pointer
MyClass* getMyClass() {
MyClass* obj = new MyClass();
//work with obj, set values...
return obj;
}
This seems to be the worst solution, you have to do memory management on your own.
Solution 3 Pass the object as a parameter
MyClass getMyClass(MyClass& obj) {
//work with obj, set values...
return obj;
}
You create a default object and set all values in the function.
I also thaught about using unique_ptr<MyCLass> but there is the same problem, that the unique_ptr is destroyed when the function scope is left.
Solution 1 does not use the copy constructor but return value optimization. It means that the object constructed in the function is actually not copied but passed to the caller of the function directly. Solution 1 is a very good option which I would recommend for non-polymorphic objects (i.e. no inheritance) which do not use too much space on the stack.
The preferred method for polymorphic objects would be Solution 2. But always think about who owns your objects, i.e. who is responsible for calling delete. A good alternative is using shared_ptr or unique_ptr.
Solution 3 does not really create the object, it only works with it once it is already created. It also does not make sense to return the object here.
Each of these has its own use cases, you can't say that one of them is better than the other or worst in all circumstances. It all boils down to your objects, how you create them, what are they supposed to interface to and where are they used.
And also there is the fourth, returning by using a shared pointer shared_ptr (in case you need shared ownership) or an auto pointer (unique_ptr or auto_ptr (sort of deprecated) ).
For example the one taking in a reference does not need to return the object too, that's an extra operation.
The one returning a pointer might not need to include a header file, a simple forward declaration might be enough (at least when you declare the function in the header file). But for this of course you will need to manually manage the memory (again: shared pointers might help here).
Related
This question already has answers here:
What is the usefulness of `enable_shared_from_this`?
(6 answers)
Closed 6 years ago.
I am new to C++11 and I came across enable_shared_from_this. I do not understand what it is trying to achieve? So I have a program that uses enable_shared_from_this.
struct TestCase: enable_shared_from_this<TestCase>
{
std::shared_ptr<testcase> getptr() {
return shared_from_this();
}
~TestCase() { std::cout << "TestCase::~TestCase()"; }
};
int main()
{
std::shared_ptr<testcase> obj1(new TestCase);
std::shared_ptr<testcase> obj2 = obj1->getptr();
// The above can be re written as below
// std::shared_ptr<testcase> obj2 = shared_ptr<testcase>(obj1);
}
My question is when I need a pointer to 'this', why not use the obj itself. Why to return a 'this' from a function of that class like using getptr() and then returning shared_from_this()????
I do not understand.
Second question, if enable_shared_from_this is NOT used, why is the dtor called twice that creates a problem, a crash!!!!
Another way I can bypass using enable_shared_from_this is like this.
Add this in class TestCase
std::shared_ptr getptr1(shared_ptr obj) {
return std::shared_ptr(obj);
}
and from main make a call this this:
std::shared_ptr bp2 = bp1->getptr1(bp1);
And done. We do not need enable_shared_from_this. Why on the earth do we need it??
A shared_ptr manages two different things. It has a pointer to its data, and a pointer to a reference counting block.
The reference counting block has a strong counter, a weak counter and a destroy operation in it.
When you std::shared_ptr<X>(pX), it creates a new reference counting block that, when the last (strong) reference goes away, it deletes the pX object.
The same thing happens when you std::shared_ptr<X>(this).
So, if you wrap an object in std::shared_ptr in two different spots, you have to different reference counting blocks, and they both want to destroy the object when they go away.
enable_shared_from_this<X> changes how this works. When you create a shared pointer to an object inheriting from it, it stores a std::weak_ptr<X> inside the enable_shared_from_this<X>. A weak pointer stores a pointer to the above reference counting block, but only "holds" a weak reference (not a strong one).
Then, when you call shared_from_this(), it does a .lock() on that weak pointer and returns a shared pointer using the reference counting block of the old one created (as stored by the weak_ptr).
Now, the above is an example implementation of what it could do: the standard mandates behavior, not implementation, and the weak_ptr is a possible way to implement it. Similarly, the reference counting block detail is just an example implementation.
The core issue is that two independent shared pointers wrapping the same pointer will try to independently manage the pointer's lifetime. enable_shared_from_this makes the first smart pointer's reference counting block be used by later shared_from_this() return values.
Short answer: you need enable_shared_from_this when you need to use inside the object itself existing shared pointer guarding this object.
Out of the object you can simply assign and copy a shared_ptr because you deal with the shared_ptr variable as is. But when you are in one of the class members then if you need to use a shared pointer pointing to self object (instead of ordinary this) and there is no such shared pointer in arguments of that method then shared_from_this() is what will help you.
Using std::make_shared(this) is absolutely unsafe as you can not have two shared pointers on the same object. While, shared_from_this() is safe because it uses weak_ptr to "resolve" already existing shared_ptr.
To be able to use shared_from_this() you must first use enable_shared_from_this in your class definition which adds a shared_from_this() method to your class.
Note, shared_from_this() can not be used in the class constructor! At that time the shared_ptr does not exist yet, so the shared_from_this() can't resolve any exisiting pointers.
And when and why one can need a shared pointer to this instead of just this it is quite other question. For example, it is widely used in asynchronous programming for callbacks binding.
I have been reading up on smart pointers and recently in class my TA said that we should never use raw pointers. Now, I've done a lot of reading online and looked at different questions on this website but I'm still confused on some aspects of smart pointers. My question is: which smart pointer would I use if I want it to be used across my program? I'll show some code.
So I have a basic Application class that makes declarations of objects from class AI. Note: I have two different smart pointers, a unique one and a shared one, for testing reasons.
// Application class in Application.h
class Application
{
public:
Application(){}
~Application(){}
//... additional non-important variables and such
unique_ptr<AI> *u_AI; // AI object using a unique pointer
shared_ptr<AI> *s_AI; // AI object using a shared pointer
//... additional non-important variables and such
void init();
void update();
};
// AI class in AI.h
class AI
{
public:
AI(){}
~AI(){}
bool isGoingFirst;
};
In the Application init function, I want to create the AI object, and then I want to use it in the update function. I am not sure if I am declaring my pointer right at all, but I know for a fact that it compiles and it works for assigning and printing out data in the init function. More code below.
void Application::init()
{
//.. other initialization's.
std::shared_ptr<AI> temp(new AI());
sh_AI = &temp;
sh_AI->isGoingFirst = true;
//.. other initialization's.
// Function ends.
}
void Application::update()
{
if(sh_AI->get()->isGoingFirst == true)
{
// Do something
}
else
{
// Do something else
}
// Other code below
}
Later in my program, the update function is called, which uses the same AI smart pointer that I declared in my class Application. What I have found out is that the smart pointer AI object is being deleted. I understand that smart pointers have automatic memory management, but is there a smart pointer that will allow you to use a it in different functions without creating any major problems, such as memory leaks or dangling references? Or am I missing the whole point of smart pointers?
I'm sorry if this was answered in another question but I read into a lot of the other questions, and while I understand more about smart pointers, I'm still learning. Thank you!
As Neil Kirk pointed out in the comments, these declarations are not what you want:
unique_ptr<AI> *u_AI; // AI object using a unique pointer
shared_ptr<AI> *s_AI; // AI object using a shared pointer
u_AI and s_AI are still objects to raw pointers. The whole point is to remove the need to manage the raw pointer directly. So now you replace them with:
unique_ptr<AI> u_AI; // AI object using a unique pointer
shared_ptr<AI> s_AI; // AI object using a shared pointer
to assign your created pointer, you use the function make_unique or make_shared:
u_AI = unique_ptr<AI>(new AI()); // Yu may be able to use make_unique like
// make_shared but it's new to C++14. may not be available
s_AI = make_shared<AI>();
Then, when you need to access them, you just pretend they are pointers, so in your update function:
if(sh_AI->get()->isGoingFirst == true)
becomes:
if(sh_AI->isGoingFirst == true)
As for when to use unique_ptr vs shared_ptr, you answer that by answering the following question: What do I want to happen when someone makes a copy of Application? i.e.:
Application app1;
app1.init();
Application app2 = app1; // ?? what happens to AI object in app2?
There are 3 possible answers:
I want there to be an extra copy of AI in app2. In this case you use unique_ptr and make sure you implement a copy constructor that does the copying.
I want app2 and app1 to share a copy of AI. In this case you use shared_ptr and the default copy constructor will do the job for you.
I don't want there ever to be a copy of Application. (Which makes sense for a class called Application). In this case it doesn't really matter (in which case I would default to unique_ptr) and remove the copy constructor:
Application(const Application&) = delete;
Short answer: Since your pointer is public, I suggest you use a shared_ptr. However, your pointer does not need to be public so if it was private you could use a unique_ptr since you only use it in your own instance.
The truth is though that it does not really matter much (and I know I'll get some downvotes with this). There are two reasons to use unique_ptr:
it never leaves your module and you just need a replacement for a naked pointer
you want to explicitly show that it is not supposed to leave your module.
On the other hand if you need to ever share the pointer (even in a read-only way) then you will have to use a shared_ptr.
A lot of times it is more convenient to use shared_ptr to begin with but for reason 2) above it is worth using unique_ptr.
Not a reason to use unique_ptr: performance. All I say is make_shared.
Now to your code
This is how you define a smart pointer:
std::shared_ptr<AI> s_AI;
std::unique_ptr<AI> u_AI;
This is how you initialize it:
s_AI = std::make_shared<AI>(); // or
s_AI = std::shared_ptr<AI>(new AI);
u_AI = std::unique_ptr<AI>(new AI);
Note that there is no std::make_unique in C++11. It's going to be in C++14 and it's not that hard to write a replacement but fact is that in C++11 there is none.
This is how you use the pointers:
s_AI->isGoingFirst;
That's it, it behaves like a normal pointer. Only if you have to pass it to a function that needs a pointer you need to use .get().
here is how you delete (empty) the pointer:
s_AI.reset();
Again, I suggest you make your pointer private. If you need to pass it out make sure you use a shared_ptr and write a getter method:
std::shared_ptr<AI> getAI() const {
return s_AI;
}
Remember that if you do this you can't assume that your AI object will be destroyed when your Application object is.
Been trying to understand shared pointer for a few days now and it feels like I cant seem to get it. Not sure if it's just to obvious or if it's too complicated. First of all, could anyone please give me an example where you would ACTUALLY use shared pointers. The examples on Wikipedia makes no sense to me. And how would you pass a shared pointer to another function or create an object with a shared pointer. So, how do you pass it around and where would you use it? ANY information or examples would be great.
Also, I have this issue where I don't know what to use. I have this function where I allocate a QFile and passes it to a function in another class. That function takes the file as a QIODevice* and then creates an object containing the file. I was wondering what the best solution would be here and how (if I should) use a shared pointer here? How can I make a shared pointer with <QFile> and pass it in where the function takes <QIODevice>. Feels like I don't get shared pointers at all...
My other approach would be to put the allocation of the QFile in a QScopedPointer. I then pass it to the class and when creating the object where the file will be stored, I use QPointer or QScopedPointer. In the end of the first calling function I should call take() right?
function () {
QScopedPointer<QFile> item(new QFile("filename"));
SomeClassObject->doStuff(item.data());
item.take();
}
---------------------------------
SomeClass::doStuff(QIODevice *item) {
_currentObject = new MyObject(item); // should _currentObject be a smartpointer?
...
}
---------------------------------
class MyObject {
QPointer<QIODevice> _item;
...
MyObject(QIODevice *item) { _item = item; }
}
So I want a way to store pointers and a way to handle them during creation if "new" throws an exception.
The point of shared pointers (and other similar wrappers for pointers) is to handle destruction of the pointer-to object properly. That is instead of having to manually make sure you delete the last copy (and only the last copy), the shared pointer takes care of it for you when it goes out of scope. The shared part means that you can create copies of this wrapper object (the shared pointer object) and it will "share" the pointer-to object between the copies (just as if you made a copy of a regular pointer) with the added benefit described above.
As for your code, SomeClass::doStuff() should have a QScopedPointer<QFile> parameter (instead of a QIODevice* one) as you are passing item to it, which has that type.
Same with MyObject's constructor: have it take a parameter of QPointer<QIODevice> or QSharedPointer<QIODevice> type. In general, everywhere where you would use pointers, use QSharedPointer instead (with the appropriate template type). This will save you from headaches related to accessing deleted objects later on.
Of course, sometimes you actually need the raw QIODevice pointer (e.g. for third-party library call), then you would use the data() member function of the shared pointer object. Just make sure you do not persist (that is store or otherwise copy beyond what's necessary) the returned raw pointer, because that will undercut the purpose of the shared pointers -- the shared pointers will not know about your extra raw pointer that is not under the management of the shared pointer objects.
EDIT:
take() releases the ownership of the pointed-to object from a scoped pointer, so when the scoped pointer is destroyed, it does not delete the object. You would ant ot use it in a situation when you transfered ownership to somthing else -- like in your case to MyObject.
I have a reference to an object and want to call a function that takes a boost::shared_ptr of this object. If I build a boost::shared_ptr to make the call when my boost::shared_ptr is canceled from the stack than the object is canceled too! This is exactly what happens when I run this code:
double f(boost::shared_ptr<Obj>& object)
{
...
}
double g(Obj& object)
{
boost::shared_ptr<Obj> p(&object);
double x = f(p);
...
}
Is there a way to make it work? How can I create in g() a boost::shared pointer that leaves my object alive at the end? I think I have to connect it to the reference counting machinery of other shared pointers that already point to object... but how?
Even if I make it work do you think this way of doing is bad design? What is the best practice to solve this kind of problems? In my code I have objects and methods that work both with shared pointer and references and I cannot work only with these or those...
A function that takes a shared_ptr is saying something about what it does. It is saying, "I want to potentially claim shared ownership of this object". If this is not true, then it is a poorly written function and shouldn't be taking a shared_ptr at all.
A function which takes a value by non-const reference to an object means that the function can modify the object, but cannot claim ownership. If you don't own something, you also can't give ownership to someone else.
Now, you could perform this trick of using an empty deleter function:
void EmptyDeleter(Obj *) {}
double g(Obj& object)
{
boost::shared_ptr<Obj> p(&object, EmptyDeleter);
double x = f(p);
...
}
However, you are now lying to f. It doesn't own object; it can't own object. It is very possible that object is a stack object that may disappear any time after f completes. If f were a member of a class, it might store the shared_ptr in a member variable. At which point, it would then have a shared_ptr to a dead object. This is exactly the sort of thing that shared_ptrs are intended to prevent.
The correct answer is for either f to not take its argument by shared_ptr (use non-const reference or non-const pointer if it is modifiable, and const& if it is not modifiable), or for g to take its argument by shared_ptr.
You may create a shared_ptr that doesn't actually free the object. Like this:
struct FictiveDisposer {
template <class T> void operator ()(T) {}
};
Obj& object = /* ... */;
boost::shared_ptr<Obj> myPtr(&obj, FictiveDisposer ());
// you may use myPtr
However you should use this carefully. If you're sure the function you're calling won't try to "save" your object for later use - there's no problem. Otherwise you must guarantee that the lifetime of the saved shared_ptr to your object won't exceed the actual lifetime of your object.
In simple words: you got the reference to the object. You didn't create it, and you may not affect its lifetime (neither shared_ptr can). Hence there may happen a situation where the object doesn't exist anymore, still it's referenced by shared_ptr. This must be avoided.
You must consider the purpose of f(). Presumably if it takes a shared_ptr, f intends to retain shared ownership of this pointer over time, past its return. Why? What is f() assuming when you pass it a shared_ptr? Once you answer this question you will be able to figure out how to code g().
If for some reason f() does not need to retain shared ownership of the pointer, then if you have control over its interface it could be rewritten to take a Obj* or Obj& instead of a shared_ptr. Any code possessing a shared_ptr could then call f by pulling the pointer out of the shared_ptr or dereferencing it.
It's usually a sign of poor design for a library interface to take a
shared_ptr (but there are exceptions). Since the function you're
calling expects to take responsibility, or at least partial
responsibility, for the object you pass it, and the rest of the code
isn't prepared for this, you're only safe solution is to clone the
object, e.g.:
double x = f( boost::shared_ptr<Obj>( new Obj( object ) ) );
But you'd really be best off finding out why f requires a
shared_ptr, and why g can't take one as an argument.
How can I create in g() a boost::shared pointer that leaves my object alive at the end?
You can give the shared pointer a custom destructor that does nothing:
boost::shared_ptr<Obj> p(&object, [](void*){});
or if your compiler doesn't support lambdas:
void do_nothing(void*) {}
boost::shared_ptr<Obj> p(&object, do_nothing);
Even if I make it work do you think this way of doing is bad design?
Yes: you lose the lifetime management that shared pointers give you, and it is now your responsibility to make sure that the object outlives all of the shared pointers.
What is the best practice to solve this kind of problems?
Decide on an ownership model for all the objects you're using, and stick to it. Shared pointers can be useful when you want to share ownership, but not otherwise. In your case f wants to share ownership, and whatever calls g seems to want exclusive ownership; it would be a good idea to think about why they want that, and whether you can change one to be compatible with the other.
std::shared_ptr<T> is to possible give multiple entities ownership of the referenced object. If an interface expects a std::shared_ptr<T> there are two possibilities:
Someone ignorantly used std::shared_ptr<T> in an interface which was meant to receive a T object or a reference or a pointer to a T object. If that is the case the author shall be educated (and if this doesn't work be released from his current duties to pursue a new career) and the interface corrected.
Since now all interfaces using a std::shared_ptr<T> are using this to possibly grant shared ownership to the object, it should be obvious that a stack allocated T isn't a suitable argument to such an interface. The only possible argument is a T object whose life-time is maintained vy a std::shared_ptr<T>.
I realize that this doesn't answer the original question but it should be clear that the only viable course of action is: don't ever try to pass an object to a function taking a std::shared_ptr<T> which can't be fully controlled by such a pointer! (the same applies to the boost version of shared pointers).
I have a pointer to a QScriptEngine that I'm passing through the overloaded class constructor of class Evaluator and assigns it to QScriptEngine *engine_ (class Property subclasses Evaluator, and calls this constructor of Evaluator, passing it an already allocated QScriptEngine). The constructor with no arguments creates the new QScriptEngine pointer (class Generic subclasses Evaluator in this way). In the destructor I test if engine_ is not NULL, delete the pointer, then assign it NULL. Should the pointer (engine_) in the derived Property now also be NULL? Something tells me this is not the case. If not, how do you deal with this situation? I need the QScriptEngine to be the same instance throughout. QScriptEngine's = operator is private, or I would be avoiding the pointer all together.
I saw some info on shared pointers (boost::shared_ptr and std:tr1::shared_ptr) in another SO question. I'm already using boost for the regex library, so boost is not out of the question if that's the best way to deal with this. Hopefully there's a non-boost way, for general C++ knowledge and future projects.
You can solve this by giving one of the classes (class A) lifetime control of that pointer, along with a 'getter' method. The other class (class B) would always call A's getter whenever it needed the pointer. That way, A remains in control of the pointer at all times. Downside is the getter function (it will probably inline, but it's still a second indirection). Also, B is going to have to check that pointer for NULL on pretty much every use.
Your other choice is to wrap the pointer in something like boost::shared_ptr which takes care of the problem (if used properly) by holding the underlying pointer, and only deleting it when all objects that share that pointer are deleted. You could write this yourself, but since you already have boost in play, I'd just use their implementation.
A third choice is to re-factor the whole thing so that you don't need a shared pointer. I'd personally never design a C++ program that needed shared pointers, just because it's a spot where memory management bugs could easily creep in over the years, but that's just me.