Phil, Unfortunately you test below confirmed my suspicion. Now could you kindly explain how your library is better than: template<typename T> struct manager { T* create(args) { all_.emplace_back(args); return &all_.back(); } void remove(T*) { ... } std::list<T> all_; }; T* serves as your node_ptr -- all pointers are valid as long as its manager instance is around. What am I missing? On 04/11/2016 12:46 PM, Phil Bouchard wrote:
On 04/10/2016 09:58 PM, Vladimir Batov wrote:
I have not looked at the implementation but from the design description I suspect I know the answer. The core design decision (if I've got it right) is that all node_ptrs are freed when its root_ptr goes out of scope irrespectively of cycles or still legitimate references. Yes, it solves the cyclic references... but also it invalidates all other references.
Sorry for the delay on this, I had to double check on Linux and Windows before answering and I ended up with this test case:
struct A { int i;
A(int i) : i(i) { std::cout << BOOST_CURRENT_FUNCTION << ": " << i << std::endl; }
~A() { std::cout << BOOST_CURRENT_FUNCTION << ": " << i << std::endl; } };
node_ptr<A> get_int() { root_ptr<A> r = make_root<A>(9); node_ptr<A> p = make_node<A>(r, 10);
return p; }
int main() { node_ptr<A> p = get_int(); std::cout << p->i << std::endl; }
And it outputs:
A::A(int): 9 A::A(int): 10 A::~A(): 9 A::~A(): 10 10
But yes the behavior is undefined in this particular case so I need to write this down in the docs. Thanks Artyom...!
Well, I've noticed you tend to make quite grandiose statements like "50 years wondering about GC", "People do not use" and "C++ will need". If I were you, I'd certainly refrain from those -- they add nothing but might show you in unfavorable light. Because if you and I disappear from the face of the earth tomorrow, the humankind, IT and C++ won't be left to "wonder for 50 years about" anything. Trust me.
Sorry I used the wrong wording but let's just say that the stakes are high.
Secondly, I work with networks/graphs. I do not use GC and C++ handles that "complexity" just fine. In fact, if I had to name an area which I'd label with the "complexity" tag, it would not be the memory management.
The same goal we all have is to write as few lines of code as possible for a given task. If I can prove that by using root_ptr, the code will be simpler then I think I will have made my point.
There is a minimum of explicitness that needs to be done by the programmer.
That argument is as good for shared_ptr/weak_ptr combination as it's good for root_ptr/node_ptr... If I were forced to deploy one or the other.
Because letting the entire memory being managed implicitly results in slow performance like we see with Java or Javascript.
Well, we are not in Java. And from C++ perspective your statement is so wrong that I do not know even where to begin. :-) But that's a different altogether topic.
Well for example it is obvious a pool of objects of the same type is must faster than a pool of objects of any size but you need to call the right pool explicitly.
But it's like you are saying one solution moves the problem somewhere else: - the GC is 100% implicit but you need "finalizers" - shared_ptr needs a weak_ptr to handle cycles - root_ptr needs a node_ptr and has potential undefined behaviors
At the end of the day it's all about the most commonly used use cases and if the library can: - reduce the amount of lines of codes - is more efficient or not - is more robust or not - is more extensible or not
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost