Assuming I know the stack frame will outlive all the copies of the shared_ptr, is there any way to create a shared_ptr to a stack object such that the reference counter is also on the stack so that there's no dynamic allocation at any point?
e.g.
SomeObject anObject;
std::shared_ptr::ref_counter refCounter; // Does this exist?
std::shared_ptr<SomeObject>(&anObject, &refCounter, [](SomeObject* obj){
obj->DoSomething();
});
The goal here being to use shared_ptr for its reference counting rather than as a smart pointer.
EDIT: I'm gonna add some more explanation to make the reasons for doing this more clear.
I'm trying to create a token that calls a function when it and all its copies are destroyed for a threading library I'm writing. Each token is essentially just a wrapper for a smart pointer to a persistent object that holds the function and calls it in its destructor. Copying the token copies the wrapper (and thus the smart pointer), but not the persistent object.
Given that these tokens may be passed to many different threads the persistent object usually needs to be on the heap, but some of the time I can actually guarantee that a particular stack frame will outlive all the copies of any tokens it creates. In those situations the persistent part of the token can be created on the stack, forgoing any expensive heap allocation.
So in some situations the smart pointer does need to actually own the object it's pointing to, but in others it doesn't.
There is no way to manage a stack allocated object with a shared pointer.
However, there should not be any need for it either. In place of the shared pointer, you can use a bare pointer or perhaps a reference. Since you know that the referenced object will outlive all users, it is safe.
I'm trying to create a token that calls a function when it and all its copies are destroyed
For that, you don't want to use a shared pointer. You should just implement your own reference counter.
you can do this but it would not be a good choice*.
SomeObject anObject;
std::shared_ptr<SomeObject>(&anObject, [](auto x){}});
coliru example
*this does not use most of the functionality of shared_ptr and is a waste, and the count can be recorded in many other ways include implement you own counting class.
I really see no reason prevent dynamic allocation. Even if you can't use heap, the dynamic allocation can happens fully on stack.
Related
I'd like to illustrate one thing I've seen:
class Something {};
void do_something(const Something *p_sth) {}
Then:
do_something(new Something());
should cause a memory leak because when you call new you should also always call delete, right? Would this be a good solution?
void do_something(const Something *p_sth)
{
delete p_sth;
}
Or is it better to use references &? I also find out that smart pointers can solve this, so delete isn't required (it seems as a good thing but I have never used it before). I just want to know what's the best solution for this to avoid the memory leak. Thanks
*Thank you all for your answers. It helped me to clear up few things. I'm also sorry for the code I posted as it was maybe too general.
Your suggestion of assuming the ownership of the pointer and deleting the object has problems.
That behaviour is not idiomatic in c++. Programmers expect that they must delete every object that they allocate with new. If a user of your function expects that they're responsible for deleting the object whose address they pass to the function, then your solution breaks apart. Also, it prevents using your function with objects that must keep existing after the call has ended:
Something* s = new s();
do_something(s);
s.foo() // oops, object was deleted, I can't use it anymore
delete s; // oops, double delete because I'm for some reason not responsible for deleting the object that I allocated
Your solution also prevents using automatically and statically allocated objects with the function.
Something s;
do_something(&s); //oops, do_something assumes that object is dynamically allocated
All of these caveats would have to be documented to the user of the function.
A raw pointer without deleting inside the function has none of these problems. Managing the callers memory should really not be the responsibility of your function. Doing that would break the single responsibility principle. There's nothing wrong with raw pointer parameters when you don't want to transfer or share ownership. If you do want to imply changes in ownership, then use smart pointers which were designed exactly for that.
Smart pointers don't have some of the above problems, but they still prevent using the function with automatic and static objects.
A reference parameter is in many cases ideal. It communicates the caller that they're still responsible for the object. As a bonus, The lack of need for addressof operator allows slightly nicer syntax. Sure, the caller may still forget to manage their memory, but as I pointed out, that shouldn't be your responsibility.
References have one potential drawback. They can't be null. If you don't need null, then it's actually an advantage.
Which solution is ideal, depends on what you need. Following is not true for all corner cases, but should hold for most common cases:
If you want to modify the object, then pass a reference.
Unless you need null, in which case use a pointer
If you just want to read the object, then
If the object is copyable, small (size less than or equal to word), doesn't cointain pointers to dynamic objects and not polymorphic, then pass by value
Otherwise or if you don't know those things because you're writing a template, pass a const reference
Unless you need null, in which case use a pointer
If you want to If you want to transfer ownership, then use unique_ptr
If you want that ownership to be shared, then use shared_ptr
Best is to use a smart pointer
class Something {};
void do_something(std::shared_ptr<Something> p_sth)
{
...
}
That way the ownership is clear when you look at the prototype as well as you get an automatic delete when you leave scope.
I just want to know what's the best solution for this to avoid the memory leak. Thanks
The best solution to ensure there are no memory leaks would be to use std::shared_ptrwhich is a smart pointer which, as soon as it does not have any references, deletes itself. This pointer is best if you have more than on reference to the same pointer. Use std::unique_ptr if there is only one reference at a given time.
This will prevent memory leaks and I also prefer using smart pointers rather than standard pointers as they are very powerful. Also, retaining to the question:
Or is it better to use references &?
Use references wherever you need to reference the object, if you delete the reference, being a smart pointer, it will delete the pointer as well (Being there are no other references to that pointer)
I hope this answers your questions :)
Prefer to avoid the use of raw pointers.
If you do not need a heap allocation and can use a stack allocated variable, then prefer to pass by reference (or even pass by value if an appropriate move constructor is in place, but that's a topic for another day).
If you need a heap allocation (for polymorphism, dependency injection, information hiding, transfer of ownership etc.) then determine what the ownership semantics will be for that object and use the appropriate smart pointer to manage those semantics.
If all else fails and you must use a raw pointer (perhaps you are dealing with a legacy interface or a C interface, or something similar) then again, clearly define your ownership semantics and document them to make it clear who is responsible for deleting the heap allocated object, etc.
If you must have a raw pointer to a stack allocated object then document that you will not be deleting the pointer and be careful about documenting the lifetime of the pointer to avoid accessing the object after it has gone out of scope.
Cleanest solution would be to avoid the pointer completely.
And yes, a reference is a good idea.
void do_something(const Something &p_sth) {}
Then you can declare your 'something' on the Stack.
void function_that_does_something()
{
Something mySomething;
do_something( mySomething );
}
It is always best to let the compiler do the cleanup for you.
From what I've read, a shared_ptr<T> does not get de-allocated until both strong references AND weak references to it are dropped.
I understand a shared object to be considered expired when there are no more strong references to it. The standard lock() function of a weak_ptr<T> therefore fails in such a case because the object is considered 'expired'.
However, if the deleter of a shared pointer is overridden such that the managed object is not deleted, then it should be valid to generated shared_ptr<T> from a weak_ptr<T> - but I cannot find the right syntax to do this.
std::shared_ptr<int> s_ptr(new(42), D());
std::weak_ptr<int) w_ptr(s_ptr);
s_ptr.reset();
s_ptr = std::shared_ptr<int>(w_ptr, false);
EDIT
To clarify this a bit further, I'm trying to construct an object pool of re-usable shared_ptr<T>. The reason behind this is because every use of shared_ptr results in one or more heap memory allocations. So I've added a deleter to every shared_ptr<T> which stores a weak_ptr<T> reference such that then the deleter gets called it should be able to re-add itself to a pool of available shared_ptr<T> objects (with managed object intact). By keeping a weak_ptr<T> stored inside the shared_ptr<T>'s deleter, it therefore shouldn't stop the deleter from being called.
The end goal is to obtain a smart pointer that doesn't do consisant heap allocation - or at least only a small number.
From what I've read, a shared_ptr does not get de-allocated until both strong references AND weak references to it are dropped.
Wrong. a std::shared_ptr has two blocks - a control block that contains reference counts, etc, then another block for the actual data.
When the shared count goes to 0, the data block is (usually) deallocated. This is why it is illegal to make a std::shared_ptr from a expired std::weak_ptr.
On another note, why would you EVER want this functionality? It ruins the entire point of std::weak_ptr, which is to be able "store" a pointer to a object stored by std::shared_ptr without incrementing its reference count.
If you want to do that, then please just use a std::shared_ptr
If pooling control blocks is a good idea, the library implementation may already be doing it. In fact, the implementation of new itself may already be doing pooling to support similar memory usage patterns.
Furthermore, you can achieve what I think your goals are by using make_shared rather than invoking new and passing it into a shared_ptr constructor; one of the reasons for the existence of this helper function is that it can be written to use a single allocation to allocate both the control block and the new object you're creating at the same time.
I have some questions about smart pointers implemented in boost library.
Is the only diffrence between shared_ptr and scoped_ptr that scoped_ptr doesn't have copy constructor and shared_ptr has it?
Should i use then scoped_ptr instead of shared_ptr always when object doesn't call copy constructor?
I also doesn't understand idea of shared/scoped array. Can't I just use std::vector instead of it?
Is the only diffrence between shared_ptr and scoped_ptr that
scoped_ptr doesn't have copy constructor and shared_ptr has it?
The difference is more fundamental than that; it has to do with how the smart pointers own the object it points to. What makes smart pointers different from dumb pointers is that the concept of ownership is a core component of their function. The ownership semantics is what differentiates the different kinds of smart pointers.
Because smart pointers "own" the thing they point to, they can do useful things like deleting objects when the smart pointers go away (this is made possible using only the rules of the language; no compiler magic is needed). This way, memory management can be made almost automatic in C++ (despite claims to the contrary, there's very little manual memory management required in modern C++).
shared_ptr implements reference-counting
semantics for
memory management. Multiple shared_ptrs can own a single object. A
shared_ptr going away does not necessarily delete the object it
points to because there may be another shared_ptr owning the
object. The last shared_ptr that owns an object and goes away will
delete the object it owns.
scoped_ptr implements exclusive-ownership semantics. Only one
scoped_ptr can own any one object. When a scoped_ptr goes away,
it will always delete the object it owns (because there's only one
owner). It's typically used as a lightweight RAII mechanism for
objects allocated on the free store.
The array versions (shared_array and scoped_array) have essentially the same semantics, but are designed specifically for arrays e.g. they use delete[] instead of delete, implements the array subscript operator, etc.
shared_ptr and shared_array also allows you to specify a custom deleter, if the default delete behavior is not appropriate for the object. scoped_ptr and scoped_array do not have that ability, since they are quite lightweight compared to shared_ptr and shared_array.
In C++11, the newest and current version of C++, there's also a unique_ptr, which is just like scoped_ptr except that you can transfer the ownership of an object to another unique_ptr. In C++03, an older but more widely supported version of C++, there's auto_ptr which is equivalent to unique_ptr except it was easy to use it in an unsafe manner by accident (which is why it is deprecated in C++11).
Should i use then scoped_ptr instead of shared_ptr always when object
doesn't call copy constructor?
Which one you choose doesn't depend on the presence of the copy-constructor, since shared_ptr and scoped_ptr does not require the object to be copy-constructible. You pick the one depending on the required ownership semantics. If the object will have multiple owners, you use shared_ptr. If the object will only have one owner and the object's existence lasts only within a scope, use scoped_ptr (hence the name scoped_ptr).
I also doesn't understand idea of shared/scoped array. Can't I just
use std::vector instead of it?
std::vector does not implement reference-counting semantics like shared_array does. std::vector is more like scoped_array, but can be copied. When you copy a std::vector, you also copy all of the elements it contains. That's not the case for scoped_array. std::vector also has functions that allow you to manipulate and examine its contents (e.g. push_back, insert, erase, etc.), but is much more heavyweight than scoped_array.
Yes. scoped_ptr does not allow for copies while shared_ptr does. But this "simple" difference makes a world of impact on both the implementation and the usage of the smart pointer.
scoped_ptr is faster and lighter than shared_ptr because no reference counting is involved. shared_ptr will count the number of assignments and not delete the object until all references have expired/gone out of scope.
Now your question regarding vectors implies that you're actually not familiar with the the concept of dynamic allocation and the difference between that and static allocation on the static. You really should look into reading a primer on C(++) and look into the reasons for dynamic allocation and when you need it.
A vector stores a list of objects. A XXX_ptr stores a pointer to a (single) dynamically-allocated object. Apples and oranges.
If you allocate memory, you can put the newly created pointer in a scoped pointer, so that IF the malloc/noew fails, the memory will be freed. This is how I usally uses it, or if it's an object that needs to be allocated on the heap, but that I want to treat it as a stack object in terms of that it will only be alive until the end of the scope.
The shared pointer is if you want to pass the pointer around and allow the object to have multiple owners. Then none of the owners needs to take responibility of the object and they can all just stop using it and be sure that it will be freed correclty. (you don't wanna free an object that you know is used by someone else)
I'd say you're thinking about it the wrong way. The question isn't whether you do call the copy constructor -- it's whether you need to call the copy constructor. In other words, you should be deciding whether to use shared_ptr or scoped_ptr not based on reading your code but based on thinking about object ownership and what objects' lifetimes should be.
Say you have an object that you want to create on the heap, not on the stack, for whatever reason (maybe it's too big to be on the stack, maybe you might want to replace it with a different object at some point, maybe you want it to be initialized late) but its lifetime should never be longer than its containing scope. A common example of this is instance variables in a class: they should often be deleted when the object they are in is deleted. Then, you should use scoped_ptr.
But sometimes you don't know when an object will be safe to delete in advance. For instance, consider an object in a lookup table. You want to return it in response to lookups, but what happens when it's deleted -- could someone still be using the object who looked it up previously? In cases like this, you can use shared_ptr, which shares the objects ownership so that it only gets deleted when nobody has a copy of the pointer anymore.
So why does anyone ever use scoped_ptr instead of shared_ptr? First of all, knowing when the destructor gets called is one of the big advantages of non-memory-managed languages like C++. Maybe the destructor is expensive, or maybe it frees a resource; it's nice to know when these things happen. Also, with shared_ptr, there's the potential for memory leaks if you create a circular reference by accident.
In general, almost every pointer you have should be "owned" -- there should be a single place in your code that news and deletes it. scoped_ptr is great for this; when you want an owned object to be passed around to non-owners you can use a bare pointer. But if you absolutely need an object's ownership to be shared, use shared_ptr -- as long as you're careful to use it correctly!
As for scoped/shared arrays, you can certainly use std::vector, but arrays are cheaper and sometimes people want the performance benefit.
shared_ptr is very different from scoped_ptr. scoped_ptr (which is now standardized in C++11 as std::unique_ptr) is simply a RAII-style smart pointer which takes ownership of a resource and then deallocates the owned resource when the pointer goes out of scope.
A shared_ptr however, may share ownership of the resource with other instances of shared_ptr. The resource stays alive as long as one or more shared_ptr instances own it. This is an automatic memory-management technique, (a form of garbage-collection) known as reference counting. It basically provides the same effect as more advanced garbage collection algorithms, except unlike other garbage collection techniques, it doesn't handle circular references.
As for using std::vector versus boost::scoped_array, yeah - scoped_array doesn't really offer much of an advantage. However, boost::shared_array offers reference counting semantics, just like shared_ptr.
Reading Alexandrescu and wikipipidia I see the pointee and the reference counter are stored on the heap. Then there is mention that reference counting is inefficient as counter must be allocated on the heap? Why isn't it stored on the stack?
Because you would lose it as soon as the current instance of the smart pointer goes out of scope.
A smart pointer is used to simulate automatic storage objects that were allocated dynamically. The smart pointers themselves are managed automatically. So when one is destroyed, anything it stores in automatic storage is also destroyed. But you don't want to lose the reference counter. So you store it in dynamic storage.
It can't be stored on the stack because then a copy of the object would also result in a copy of the refcount, which would defeat its purpose.
As others have pointed out, the stack isn't an appropriate place to keep the reference count because the object may outlive the current stack frame (in which case the reference count would go away!)
It's worth noting that some of the inefficiencies associated with putting the reference count on the heap can be overcome by storing it "together" with the object itself. In boost, this can be accomplished by using boost::make_shared (for shared_ptr's) or boost::intrusive_ptr.
There are different types of smart pointers, designed for different purposes. The pointer you are talking about is a shared smart pointer (std::shared_ptr), which helps sharing object ownership from multiple places. All the copies of shared_ptr increment and decrement the same counter variable, which is placed on the heap, as it needs to be available to all copies of the shared_ptr even after the first copy dies.
So, shared_ptr internally keeps two pointers: to the object and to the counter. Pseudocode:
class SharedPointer<T> {
public:
// ...
private:
T* obj;
int* counter;
}
By the way, when you create object with std::make_shared, the implementation may optimize allocations by allocating enough memory to hold both the counter and the object and then constructing them side-by-side.
This trick at its extreme gives us an intrusive reference counting pattern: the object internally holds its counter and provides AddRef and Release functions to increment and decrement it. The you can use intrusive smart pointer, e.g. boost::intrusive_ptr, which uses this machinery and thus doesn't need to allocate another separate counter. This is faster in terms of allocations, but requires to inject the counter to the controlled class definition.
Also, when you don't need sharing object ownership and only need to control it's lifetime (so that is gets destructed when function returns), you can use the scoped smart pointer: std::unique_ptr or boost::scoped_ptr. It doesn't need the counter altogether, as only one copy of the unique_ptr exists.
sometimes I see in various C++ programs, objects declared and used like so:
object *obj = new object;
obj->action();
obj->moreAction();
//etc...
Is there any benefit of doing that, instead of simply doing:
object obj;
obj.action();
obj.moreAction();
//etc
Yes - you can store the pointer in a container or return it from the function and the object will not get destroyed when the pointer goes out of scope. Pointers are used
to avoid unnecessary copying of object,
to facilitate optional object creation,
for custom object lifetime management,
for creating complex graph-like structures,
for the combinations of the above.
This doesn't come for free - you need to destroy the object manually (delete) when you no longer need it and deciding when this moment comes is not always easy, plus you might just forget to code it.
The first form, allocating objects on the heap, gives you full control of (and full responsibility for) the object's live time: you have to delete obj explicitly.
In the second form, the object is automatically and irrevocably destroyed when obj goes out of score (when leaving the current code block).
One other reason no-one has mentioned.
The stack is typically 1Mb, so creating large objects must be done on the heap ( with new)
Basically, you should only use "new" if you want an object to live beyond the lifetime of the scope you create it in. For eg:
X* g(int i) { /* ... */ return new X(i); } // the X outlives the call of g()
If you want an object to live in a scope only, don't use "new" but simply define a variable:
{
ClassName x;
// use x
}
It comes down to having more control over the lifecycle of the object in question (when using new).
Yes there is a good reason: you have much more chance to have a correct program when using the latter form..
The problem is that the former form (pointer) is a Cism, in C++ you should use a smart pointer to ensure proper destruction of the object at the end of its life.
Now, if you use std::auto_ptr<Object> obj(new Object()); you have 3 benefits:
you now manage the life cycle of your object explicitly (but cannot forget it)
you can store you object into a container with polymorphism
you do not clog the stack, and thus have less risk of running into a stack overflow
one can ask in a opposite way: when should you use strange first option? basically if you want to allocate big object, because if you don't have to do it and you can put it on the stack it will be much faster option: this is one of main advantages of using C++ over JAVA, which puts all objects on the heap. and this benefit is specially true when dealing with many, many allocations of little objects: put them on stack to increase speed. there is cost overhead of dereferencing pointer. you can find here info about boost pool library which provides us with tools to manage such allocations.