Comments (6)
Hi,
a) the implementation basically requires atomic variables. However, there are usecases where one wants intrusive_ptr but not including atomic operations, for example because they pull in extra library dependencies on some embedded architectures or because they make the operation slower (memory barriers) although in the specific design the MT-safety might be not required.
Good question. I am aware of that sometimes people don't want reference counts with atomicity just because there could be no more than one thread - for example when writing single-threaded programs. Basically, in order to make reference count increment/decrement operations overrideable I suggest use of argument dependent lookup (you know it, no?). The default version is used only in absence of user-provided ones - just like std::swap
.
b) I don't see the point of intrusive_weak_ptr. Maybe it's just missing documentation?
intrusive_weak_ptr
is to intrusive_ptr
what weak_ptr
is to shared_ptr
. It is as simple as that. Saying you have an object of type A
holding an intrusive_ptr
to an object B
, which in turn holds an intrusive_ptr
to A
, you end up with a circular dependency. intrusive_weak_ptr
is there to break such dependencies. intrusive_ptr
asserts ownership, and intrusive_weak_ptr
disclaims ownership. You .lock()
an intrusive_weak_ptr
to get an intrusive_ptr
which is potentially null (a null intrusive_ptr
is always empty. This is not the case for shared_ptr
, whose null-ness and emptiness are orthogonal).
Trivia
It should be noted that, when constructing a weak_ptr
from a shared_ptr
, the control block containing reference counters (there are typically two reference counters: The strong reference count is what will be returned by use_count()
and the weak reference count is used to constrain the lifetime of the control block itself) will have already been allocated by either make_shared()
or the constructor of the shared_ptr
, so the entire construction merely increments the weak reference count hence throws no exceptions. This is not the case for intrusive_weak_ptr
, which allocates the control block in its constructor. The possibility of exceptions can however be eliminated by calling .reserve_weak()
on an object before it is assigned to a intrusive_weak_ptr
.
Despite this flaw, copying an intrusive_ptr
increments the strong reference count only, in contrast to copying a shared_ptr
which increments both. Another advantage of intrusive_ptr
is that, if you don't use intrusive_weak_ptr
, you don't pay for the overheads brought by the weak reference count, which is not possible in case of shared_ptr
.
from intrusive_ptr.
There are some considerations allowing incrementing/decrementing reference counts using user-defined manipulators:
namespace my {
class base : public std::intrusive_base<base> {
protected:
virtual ~base(){ }
};
class derived : private base { // Use private inheritance.
public:
~derived() override { }
public:
std::intrusive_ptr<base> get_base_ptr(){
return std::intrusive_ptr<base>(this); // Okay.
}
};
// Returns `true` if the reference count was not zero and has been incremented.
// Returns `false` if the reference count was zero.
bool try_add_ref(base &b){
return b.std::intrusive_base<base>::try_add_ref();
}
// The behavior is undefined if the reference count was zero.
void add_ref(base &b){
b.std::intrusive_base<base>::add_ref();
}
// Decrements the reference count.
// Returns `true` if the reference count has been decremented to zero.
// Returns `false` otherwise.
// The behavior is undefined if the reference count was zero.
bool drop_ref(base &b){
return p.std::intrusive_base<base>::drop_ref();
}
} // namespace my
void check(){
std::intrusive_ptr<my::derived> pd = std::make_intrusive<my::derived>();
std::intrusive_ptr<my::base> pb = pd->get_base_ptr(); // Okay.
pb.reset(); // Maybe this can use ADL to decrement the reference count of
// an object of type `my::base`...
pd.reset(); // ... but how about this? `my::base` is a PRIVATE base hence inaccessible here.
}
from intrusive_ptr.
Another solution to a) would be using virtual add_ref()
, try_add_ref()
and drop_ref()
functions. Virtual functions are nothing better than atomic counters essentially .
from intrusive_ptr.
Well, thanks for commenting. Indeed, I have not looked deep enough and I overlooked the part about weak_view. So this basically means that you recreated the conditions for weak_ptr by storing the control block optionally in a separate object allocated on stack.
Not sure I like this decision - for a generic solution it's probably ok but the user should be aware of the additional costs of this implementation. Because, I said, one usually looks for intrusive_ptr for performance reasons.
Regarding the addition of alternative behavior - yes, virtual calls might be a way to get this. But then again, it shifts costs to runtime which becomes a questionable thing. And in overall, looking at the code size and complexity, I am slightly reluctant to any of the proposals.
So, thanks for your work! But sorry, I will stay with my own little intrusive pointer implementation for now, which appears more pragmatic for the mentioned usecase.
from intrusive_ptr.
Well, thanks for commenting. Indeed, I have not looked deep enough and I overlooked the part about weak_view. So this basically means that you recreated the conditions for weak_ptr by storing the control block optionally in a separate object allocated on stack.
It is not 'allocated on stack'. It is dynamic.
Not sure I like this decision - for a generic solution it's probably ok but the user should be aware of the additional costs of this implementation. Because, I said, one usually looks for intrusive_ptr for performance reasons.
Indeed. Elimination of separated allocation of the object and its control block is what people benefit from make_shared
. Well, intrusive_ptr
attracts people who don't make use of weak semantics.
Regarding the addition of alternative behavior - yes, virtual calls might be a way to get this. But then again, it shifts costs to runtime which becomes a questionable thing. And in overall, looking at the code size and complexity, I am slightly reluctant to any of the proposals.
More than that, if a non-template class has a virtual function (_Impl_intrusive_ptr::_Ref_count_base
), we must provide an out-of-line definition of its RTTI, otherwise dynamic_cast
'ing across dynamic library boundaries might fail, which prevents this library from being header-only.
So, thanks for your work! But sorry, I will stay with my own little intrusive pointer implementation for now, which appears more pragmatic for the mentioned usecase.
You are welcome.
from intrusive_ptr.
I am closing this issue for now. Please open an new issue for any further discussion.
from intrusive_ptr.
Related Issues (6)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from intrusive_ptr.