- Threaded Tree Causes SegFault - 5 Updates
- Another test of zapcc - 5 Updates
- Memory Management Techniques - 8 Updates
- Threaded Binary Tree - 4 Updates
- Insert Not Working - 2 Updates
- Threaded Binary Tree - 1 Update
xerofoify <xerofoify@gmail.com>: Nov 28 01:11PM -0800 Greetings All, Seems the tree is now segfaulting and can't figure out why. I am getting very annoyed with and have no idea why. I have tried everything I can think of to no result, I will post the code again. But can someone show me a complete working insert and constructor as I have no idea why this doesn't work. #include <iostream> using namespace std; //Threaded Binary Tree Class that is templated to hold Node pointers with data type T template <class T> class ThreadedTree{ //Internal Node Class for each Node in the tree struct Node{ //Constructor for Node Class //Takes the data to be held as a paramater and Node pointers for left and right elements //defaults are nullptr for left and right elements and data is set to default value for data type T Node(const T& data = T{}, Node* left = nullptr, Node* right = nullptr){ data_ = data; right_ = right; left_ = left; } T data_; Node*left_; Node* right_; bool leftThread; bool rightThread; //Finds the leftmost from the struct Node pointer passed in, returns nullptr if the Node is nullptr struct Node* leftMost(struct Node *n){ if (n == nullptr){ return nullptr; } while (n->left_ != nullptr){ n = n->left_; } return n; } //Finds the rightmost from the struct Node pointer passed in, returns nullptr if the Node is nullptr struct Node* rightMost(struct Node *n){ if (n == nullptr){ return nullptr; } while (n->right_ != nullptr){ n = n->right_; } return n; } }; Node* root_; void cleanup(Node* subtreeroot){ if(subtreeroot==root_){ return; } if (subtreeroot){ cleanup(subtreeroot->left_); cleanup(subtreeroot->right_); delete subtreeroot; } } public: class const_iterator{ protected: friend class ThreadedTree; //Constructor that sets curr_ internal Node for iterator to Node passed in agrument Node* c const_iterator(Node* c){ curr_ = c; } Node* curr_; //Checks current node is not nullptr bool checkData(){ return curr_ == nullptr; } public: //Constructor that sets curr_ internal iterator Node to nullptr const_iterator(){ curr_ = nullptr; } //Takes a interger and makes iterator point to next right element before returning previous element const_iterator operator++(int){ if(curr_==nullptr){ } const_iterator old = *this; if (curr_->rightThread){ curr_ = curr_->right_; } else { curr_ = curr_->left_; curr_ = curr_->rightMost(curr_); } return const_iterator(old); } //Takes a interger and makes iterator point to next left element before returning previous element const_iterator operator--(int){ const_iterator old =*this; if(curr_==nullptr){ return nullptr; } if (curr_->leftThread){ curr_ = curr_->left_; } else{ curr_ = curr_->right_; curr_ = curr_->leftMost(curr_); } return const_iterator(old); } //Takes no arguments and makes iterator point to next right element const_iterator operator++(){ if (curr_==nullptr){ return nullptr; } if(curr_->rightThread){ curr_= curr_->right_; } else{ curr_ = curr_->left_; curr_ = curr_->rightMost(curr_); } return iterator(curr_); } //Takes no arguments and makes iterator point to next left element const_iterator operator--(){ if(curr_==nullptr){ return nullptr; } if(curr_->leftThread){ curr_ = curr_->right_; } else{ curr_ = curr_->right_; curr_ = curr_->leftMost(curr_); } return iterator(curr_); } //Takes no arguments and returns internal Node of iterator const T& operator*(){ return curr_->data_; } //Takes const_iterator reference and sees if internal element equals passed reference's element bool operator==(const const_iterator& rhs) const{ return curr_ == rhs.curr_; } //Takes const_iterator reference and sees if internal element does not equals passed reference's element bool operator!=(const const_iterator& rhs) const{ return curr_ != rhs.curr_; } friend class ThreadedTree; }; class iterator :public const_iterator{ protected: //Constructor that sets curr_ internal iterator Node to Node passsed iterator(Node* c) :const_iterator(c){} public: // Constructor that sets curr_ internal iterator Node to nullptr iterator() :const_iterator(){} const T& operator*(){ return this->curr_->data_; } iterator operator++(int){ iterator old = *this; if(this->checkData()) { return nullptr; } if (this->curr_->rightThread){ this->curr_ = this->curr_->right_; } else{ Node* pass = this->curr_->left_; this->curr_ = this->curr_->left_; this->curr_ = this->curr_->rightMost(pass); } return iterator(old); } //Takes a interger and makes iterator point to left element before returning previous element iterator operator--(int){ const_iterator old = *this; if(this->checkData()){ return nullptr; } if (this->curr->leftThread){ this->curr = this->curr->right_; } else{ Node* pass = this->curr_->left_; this->curr_ = this->curr_->right_; this->curr_ = this->curr_->leftMost(pass); } return iterator(old); } //Takes a interger and makes iterator point to next right element before returning previous element iterator operator++(){ if(this->checkData()){ return nullptr; } if (*this->curr->rightThread){ this->curr = this->curr->right_; } else{ this->curr_ = this->curr_->left_; this->curr_ = this->curr_->rightMost(this->curr_->right_); } return iterator(this->curr_); } //Takes no arguments and makes iterator point to next right element iterator operator--(){ if(this->checkData()){ return nullptr; } if(this->curr->leftThread){ this->curr = this->curr->right_; } else{ this->curr_ = this->curr_->right_; this->curr_ = this->curr_->leftMost(this->curr_->left_); } return iterator(this->curr_); } friend class ThreadedTree; }; //Constructor that creates new Tree, takes no arguments and sets tree to new state ThreadedTree(){ root_ = new Node(); root_->leftThread = true; root_->leftThread = false; } void printTree() { Node *tmp = root_, *p; for (;;) { p = tmp; tmp = tmp->right_; if (!p->rightThread) { while (!tmp->leftThread) { tmp = tmp->left_; } } if (tmp == root_) break; cout<<tmp->data_<<" "; } cout<<endl; } //Takes const reference of type T and inserts it into tree, returns iterator to inserted Node iterator insert(const T& data){ Node* p = root_; for (;;){ if (p->data_ < data){ if (p->leftThread) break; p = p->right_; } else if (p->data_ > data){ if (p->rightThread) break; p = p->left_; } } Node* tmp = new Node(); tmp->data_ = data; tmp->rightThread = tmp->leftThread = true; if (p->data_ < data){ tmp->right_ = p->right_; tmp->left_ = p; p->right_ = tmp; p->rightThread = false; return iterator(p->right_); } else{ tmp->right_ = p; tmp->left_ = p->left_; p->left_ = tmp; p->leftThread = false; return iterator(p->left_); } } //Takes const reference of type T and finds it in table,if not found returns nullptr iterator find(const T& data) const{ Node *tmp = root_->left_; for (;;){ if (tmp->data_ > data){ if (tmp->rightThread) return nullptr; tmp = tmp->right_; } else if (tmp->data_ < data){ if (tmp->leftThread) return nullptr; tmp = tmp->left_; } else{ return iterator(tmp); } } } //Takes no arguments and returns leftmost Node in Tree as iterator iterator begin(){ Node* curr = root_; if (curr->right_ == nullptr && curr->left_ == nullptr) { return nullptr; } if (curr != nullptr) { while(curr->left_!=nullptr){ curr = curr->left_; } } return iterator(curr); } //Takes no arguments and returns rightmost Node in Tree as iterator iterator end(){ return nullptr; } //Takes no arguments and returns leftmost Node in Tree as const_iterator const_iterator begin() const{ Node* curr = root_; if (curr->right_ == nullptr && curr->left_ == nullptr) { return nullptr; } if (curr != nullptr) { while(curr->left_!=nullptr){ curr = curr->left_; } } return const_iterator(curr); } //Takes no arguments and returns rightmost Node in Tree as iterator const_iterator end() const{ return nullptr; } //Destructor that destroys tree ~ThreadedTree(){ cleanup(root_); } }; |
legalize+jeeves@mail.xmission.com (Richard): Nov 28 09:32PM [Please do not mail me a copy of your followup] xerofoify <xerofoify@gmail.com> spake the secret code >Seems the tree is now segfaulting and can't figure out why. Use a debugger and examine the cause of the segfault. Step through the code in the debugger leading up the to segfault after you've discovered the cause. Write unit tests on your code to verify all control paths as you develop them. -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Terminals Wiki <http://terminals-wiki.org> The Computer Graphics Museum <http://computergraphicsmuseum.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
xerofoify <xerofoify@gmail.com>: Nov 28 01:47PM -0800 On Monday, November 28, 2016 at 4:32:08 PM UTC-5, Richard wrote: > The Terminals Wiki <http://terminals-wiki.org> > The Computer Graphics Museum <http://computergraphicsmuseum.org> > Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> I have tried that everything. I even drew it up hand. I don't get how it's not working. Nothing about that code doesn't make sense to me. I really have no idea how it doesn't as in a debugger it hits: if (p->data_ < data){ before crashing even through roots data is properly set here: Node(const T& data = T{}, Node* left = nullptr, Node* right = nullptr){ so can to explain how T{} is not setting the data. |
legalize+jeeves@mail.xmission.com (Richard): Nov 28 10:22PM [Please do not mail me a copy of your followup] xerofoify <xerofoify@gmail.com> spake the secret code >> Write unit tests on your code to verify all control paths as you >> develop them. >I have tried that everything. Upload your source and unit tests to a github repo and post the link. -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Terminals Wiki <http://terminals-wiki.org> The Computer Graphics Museum <http://computergraphicsmuseum.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
Paavo Helde <myfirstname@osa.pri.ee>: Nov 29 12:27AM +0200 On 28.11.2016 23:47, xerofoify wrote: > I have tried that everything. I even drew it up hand. I don't get how it's not working. Nothing about that code doesn't make sense to me. I really have no idea how it doesn't as in a debugger it hits: > if (p->data_ < data){ > before crashing even through roots data is properly set here: What debugger does not show you that p is null at that point? You are happily updating p in this loop, without ever checking if it becomes null or not: Node* p = root_; for (;;) { if (p->data_ < data) { if (p->leftThread) break; p = p->right_; } else if (p->data_ > data) { if (p->rightThread) break; p = p->left_; } } Moreover, if here p->data_==data, this thing goes into infinite loop. |
"Öö Tiib" <ootiib@hot.ee>: Nov 27 03:43PM -0800 On Sunday, 27 November 2016 23:39:16 UTC+2, Alf P. Steinbach wrote: > > http://... > That looks like spam. > Even your last name looks like spam. Yes, the author clearly just wanted that we click the link to his blog about testing zapcc. > How about a few words about what zapcc is and what the test showed, and > why you think it's relevant to discuss here or relevant for us to know > about? zapcc is AFAIK attempted clone of clang to commercial c++ compiler made by a company of Israel that tries to achieve improved speed of compilation. Whatever they have done is closed source and in beta test. |
bitrex <bitrex@de.lete.earthlink.net>: Nov 27 07:32PM -0500 On 11/27/2016 06:43 PM, Öö Tiib wrote: > zapcc is AFAIK attempted clone of clang to commercial c++ compiler made > by a company of Israel that tries to achieve improved speed of > compilation. Whatever they have done is closed source and in beta test. So people are willing to pay money for a C++ compiler where its main selling point is compilation speed, and not security or guaranteed behavior, etc? Weird. |
bitrex <bitrex@de.lete.earthlink.net>: Nov 27 07:33PM -0500 On 11/27/2016 07:32 PM, bitrex wrote: > selling point is compilation speed, and not security or guaranteed > behavior, etc? > Weird. Is this something targeted at the HFT software industry, maybe? |
Vir Campestris <vir.campestris@invalid.invalid>: Nov 28 09:44PM On 27/11/2016 23:43, Öö Tiib wrote: > zapcc is AFAIK attempted clone of clang to commercial c++ compiler made > by a company of Israel that tries to achieve improved speed of > compilation. Whatever they have done is closed source and in beta test. Is that even legal? Surely Clang's licence requires you to publish derived works? (asd no, I haven't checked) Andy |
legalize+jeeves@mail.xmission.com (Richard): Nov 28 10:24PM [Please do not mail me a copy of your followup] Vir Campestris <vir.campestris@invalid.invalid> spake the secret code >> compilation. Whatever they have done is closed source and in beta test. >Is that even legal? Surely Clang's licence requires you to publish >derived works? (asd no, I haven't checked) Clang uses a BSD license which doesn't forbid commercial derivatives. <http://clang.llvm.org/features.html#license> -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Terminals Wiki <http://terminals-wiki.org> The Computer Graphics Museum <http://computergraphicsmuseum.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
"Christopher J. Pisz" <cpisz@austin.rr.com>: Nov 27 09:02PM -0600 I am still playing with making custom memory management and learning about it. Out of the 15 example memory managers I've found Googling things up, ZERO of them work if you do not know the size of the type you will be allocating and only allocate that type. In other words, I cannot find a memory manager that allows me to allocate space for more than one type. Additionally, the design of the type is coupled to the memory manager, because it contains an overload of new and delete just for that class type. The idea of having my own memory management seems lucrative, because there is often a time where I know I might be allocating some 10,000-1000,000 objects. We'd significantly improve performance if we allocated a large chuck of space up front. For example, this simple memory manager I found on IBM's site, that they used as their first example. https://www.ibm.com/developerworks/aix/tutorials/au-memorymanager/ (headers only) //------------------------------------------------------------------------------ class SpecificToSimpleMM : public ComplexNumber { public: SpecificToSimpleMM(double realPart, double SpecificToSimpleMMPart); SpecificToSimpleMM(const SpecificToSimpleMM & rhs); ~SpecificToSimpleMM(); // These two operators call on a global instance of the memory manager to allocated and free space void * operator new(size_t size); void operator delete(void * pointerToDelete); }; //------------------------------------------------------------------------------ // Memory Manager that allocates space for multiple objects, of a specific type, at a time // // Customized for objects of type SpecificToSimpleMM and works only in single-threaded environments. // Keeps a pool of SpecificToSimpleMM objects available and has future allocations occur from this pool. class SimpleMemoryManager : public IMemoryManager { // Node in the memory pool struct FreeStoreNode { FreeStoreNode * m_next; }; void expandPoolSize(); void cleanUp(); // The memory pool FreeStoreNode * m_freeStoreHead; public: SimpleMemoryManager(); virtual ~SimpleMemoryManager(); virtual void * allocate(size_t); virtual void free(void *); }; They had two more; A "bitmapped memory manager" and a "freelist memory manager", but reading over thier article, it seems to me that both can only handle one type of object. Can you point me to some memory management techniques that allow for allocating different amounts of storage and are not designed to work with one type only? |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 28 06:58AM +0100 On 28.11.2016 04:02, Christopher J. Pisz wrote: [snip] > Can you point me to some memory management techniques that allow for > allocating different amounts of storage and are not designed to work > with one type only? Andrei's Loki library has a fast small objects allocator, as I recall. It's open source. Cheers & hth., - Alf |
Paavo Helde <myfirstname@osa.pri.ee>: Nov 28 10:37AM +0200 On 28.11.2016 5:02, Christopher J. Pisz wrote: > memory manager that allows me to allocate space for more than one type. > Additionally, the design of the type is coupled to the memory manager, > because it contains an overload of new and delete just for that class type. What do you mean? A memory allocator often needs to allocate memory for other types than its "native" type. There is a special rebind mechanism for that. In C++ a custom memory allocator is a template, exactly because it needs to be instantiated for different types. In your example there was no template, so I assume it was illustrating something else than C++ memory allocators. Maybe you are confused what a memory allocator is in C++. It is not something which you call from some overridden operator new (though it may be called from there as well). No, a custom memory allocator is primarily something which you can pass as a template argument for std::vector or std::allocate_shared, etc. From what I see in the debugger, my allocator template is often called through the rebind mechanism for types like 'char' or std::_Container_proxy, etc. > there is often a time where I know I might be allocating some > 10,000-1000,000 objects. We'd significantly improve performance if we > allocated a large chuck of space up front. These are called pooled memory allocators. There are many of them existing, no need to reinvent wheels. [...] > Can you point me to some memory management techniques that allow for > allocating different amounts of storage and are not designed to work > with one type only? http://en.cppreference.com/w/cpp/memory/allocator discusses rebind, with some examples. In C++17 the rebind mechanism seems to be moved over to allocator_traits, with some cleaner syntax. hth Paavo |
"Christopher J. Pisz" <cpisz@austin.rr.com>: Nov 28 03:59AM -0600 On 11/28/2016 2:37 AM, Paavo Helde wrote: > to be instantiated for different types. In your example there was no > template, so I assume it was illustrating something else than C++ memory > allocators. Memory Management is not equivalent to C++ std::allocator from what I am finding, and I have not found any that actually use post C++11 allocator requirements, that works, beyond simply adding a logging features and the like. Most everything I find is a stand alone mememory management scheme that does not use allocators at all. > may be called from there as well). No, a custom memory allocator is > primarily something which you can pass as a template argument for > std::vector or std::allocate_shared, etc. Nope. I know what it is. I've read up on it for a week now. Even if I was to find a working example of an Allocator post C++11 that worked and did anything beneficial, the actual memory management technique would be separate from the allocator itself. >> allocated a large chuck of space up front. > These are called pooled memory allocators. There are many of them > existing, no need to reinvent wheels. I'd like to reinvent the wheel to learn how the wheel works if nothing else. There seems to be demand for this kind of thing. > http://en.cppreference.com/w/cpp/memory/allocator discusses rebind, with > some examples. In C++17 the rebind mechanism seems to be moved over to > allocator_traits, with some cleaner syntax. That example doesn't actually accomplish anything though. It just uses the default. It does not show anyone how they would actually implement their own allocator, one that contains state, or how to implement the actual memory management. Here are examples of what I am finding: https://www.ibm.com/developerworks/aix/tutorials/au-memorymanager/ http://anki3d.org/cpp-allocators-for-games/ http://www.codinglabs.net/tutorial_memory_pool.aspx https://jfdube.wordpress.com/2011/10/06/memory-management-part-2-allocations-tracking/ All of these are memory managers that all work with particular types. None of them are actually put to use in an allocator. Then I find links on allocator: http://en.cppreference.com/w/cpp/memory/allocator http://www.drdobbs.com/the-standard-librarian-what-are-allocato/184403759#1 https://rawgit.com/google/cxx-std-draft/allocator-paper/allocator_user_guide.html#examples None of which have any memory management working with them, or have one that actually compiles and works without severe problems. From what I understand this is a two part problem. Firstly, actually learning the memory management techniques, then finding one I can use for various types. Secondly, implementing it in a way that it can be used with an allocator. Neither endevour is going very well... |
Paavo Helde <myfirstname@osa.pri.ee>: Nov 28 06:53PM +0200 On 28.11.2016 11:59, Christopher J. Pisz wrote: > finding, and I have not found any that actually use post C++11 allocator > requirements, that works, beyond simply adding a logging features and > the like. If you are interested in how exactly a memory manager works in low level then I am pretty sure they are just working with bytes of memory, no object type involved. For a C++-compliant memory allocator, see e.g. "https://www.threadingbuildingblocks.org/tutorial-intel-tbb-scalable-memory-allocator" Their C++-compliant allocator is just a wrapper around C-style interface using untyped memory blocks: scalable_malloc() and scalable_free(). One can use these directly as well. Here you have low-level implementation which does not care about types, and the high-level C++-compliant allocator template which works for any type (see the rebind member). Quote from TBB scalable_allocator.h: //! Meets "allocator" requirements of ISO C++ Standard, Section 20.1.5 /** The members are ordered the same way they are in section 20.4.1 of the ISO C++ standard. @ingroup memory_allocation */ template<typename T> class scalable_allocator { public: typedef typename internal::allocator_type<T>::value_type value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; template<class U> struct rebind { typedef scalable_allocator<U> other; }; scalable_allocator() throw() {} scalable_allocator( const scalable_allocator& ) throw() {} template<typename U> scalable_allocator(const scalable_allocator<U>&) throw() {} pointer address(reference x) const {return &x;} const_pointer address(const_reference x) const {return &x;} //! Allocate space for n objects. pointer allocate( size_type n, const void* /*hint*/ =0 ) { return static_cast<pointer>( scalable_malloc( n * sizeof(value_type) ) ); } //! Free previously allocated block of memory void deallocate( pointer p, size_type ) { scalable_free( p ); } //! Largest value for which method allocate might succeed. size_type max_size() const throw() { size_type absolutemax = static_cast<size_type>(-1) / sizeof (value_type); return (absolutemax > 0 ? absolutemax : 1); } #if __TBB_ALLOCATOR_CONSTRUCT_VARIADIC template<typename U, typename... Args> void construct(U *p, Args&&... args) { ::new((void *)p) U(std::forward<Args>(args)...); } #else // __TBB_ALLOCATOR_CONSTRUCT_VARIADIC #if __TBB_CPP11_RVALUE_REF_PRESENT void construct( pointer p, value_type&& value ) { ::new((void*)(p)) value_type( std::move( value ) ); }
Subscribe to:
Post Comments (Atom)
|
No comments:
Post a Comment