Created
April 21, 2012 16:24
-
-
Save tomthorogood/2438152 to your computer and use it in GitHub Desktop.
Managed Array of Pointers in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /*! | |
| A class to manage arrays of pointers, all of which can be accessed individually. | |
| Copyright (C) 2012 Tom Thorogood | |
| This program is free software: you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation, either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| I was plagued with memory management using the Wt library. In order to keep neat code, I wanted arrays of widgets, which in Wt are all allocated on the heap, instead of the stack. To get around the issues I was having, I wrote this class, which allocates a managed array of pointers that can be accessed individually (via an enum, for example), and are managed by the class. | |
| Basically, anytime a new slot is allocated, the corresponding bit within the flags bitset is set, and is reset anytime that slot is deallocated. This guards against double deletes. In the class destructor, all of the bits are tested, and if they are set, the corresponding slot in the array is deleted. | |
| The bitset is allocated on the stack, so it will automatically be deleted when it goes out of scope. | |
| To implement this class, you can use it as-is, or you can redefine the alloc() and/or allocAt method(s) to include constructor arguments for the class it will be storing. | |
| Here a complete | |
| example: | |
| class Foo | |
| { | |
| private: | |
| int myInt; | |
| public: | |
| Foo(anInt) { myInt = anInt; } | |
| int get() { return myInt;} | |
| }; | |
| public FooArray : public PtrArray <8, Foo> | |
| { | |
| public: | |
| Foo* alloc(int anInt) | |
| { | |
| int next = this->gap(); | |
| this->allocator[next] = new Foo(anInt); | |
| this->flags.set(next); | |
| return this->allocator[next]; | |
| } | |
| Foo* allocAt(int loc, int anInt) | |
| { | |
| if (this->flags.test(loc)) | |
| { | |
| delete this->allocator[loc]; | |
| } | |
| this->allocator[loc] = new Foo(anInt); | |
| this->flags.set(loc); | |
| return this->allocator[loc]; | |
| } | |
| }; | |
| int main() | |
| { | |
| FooArray myFoos; | |
| Foo* fooPtr; | |
| myFoos.alloc(8); // Creates a new Foo object at slot [0] in the array, setting Foo::myInt to 8 | |
| myFoos.rem().alloc(15) // Replaces the previously allocated Foo object. | |
| myFoos.alloc(8); // Creates a new Foo object at slot [1] in the array. | |
| myFoos.allocAt(4, 12); // Creates a new Foo object at slot [4] in the array, setting Foo::myInt to 12 | |
| std::cout << *myFoos.dig(4)->get() << std::endl // prints '12' | |
| fooPtr = myFoos.alloc(18); | |
| std::cout << fooPtr->get() << std::endl // prints '18' | |
| return 0; | |
| // myFoos destructor is called, which will delete slots 0, 1, and 4 in the array. The rest are already free. | |
| } | |
| */ | |
| template <size_t max, class PointerType> | |
| class PtrArray { | |
| protected: | |
| PointerType *allocator[max]; | |
| std::bitset<max> flags; | |
| public: | |
| /*! Default constructor initializes all members of the array to 0. | |
| */ | |
| PtrArray(){ | |
| for (int i = 0; i < max; i++) | |
| { | |
| allocator[i] = 0; | |
| } | |
| flags.reset(); | |
| } | |
| virtual ~PtrArray() | |
| { | |
| while (!flags.none()) | |
| { | |
| int del = top(); | |
| delete allocator[del]; | |
| flags.set(del, false); | |
| } | |
| } | |
| /*! returns a pointer to the next item in the stack after | |
| * calling the new operator to initialize it. If the max | |
| * stack size has already been reached, it deletes the top | |
| * level and replaces it. | |
| * | |
| * This is a virtual method because if the PointerType requires | |
| * additional arguments in its constructor, this needs to be | |
| * overwritten in order to include them. | |
| * | |
| * @return a pointer to a PointerType object. | |
| */ | |
| virtual PointerType* alloc() | |
| { | |
| int next = gap(); | |
| allocator[next] = new PointerType(); | |
| flags.set(next); | |
| return allocator[next]; | |
| } | |
| /*! Allocates a specific slot in the array | |
| * | |
| * @precondition loc must be less than max. | |
| * @param a location within the array | |
| * @return a pointer to the newly (re)allocated location in memory storing a PointerType object. | |
| */ | |
| virtual PointerType* allocAt(int loc) | |
| { | |
| if (flags.test(loc)) | |
| { | |
| delete allocator[loc]; | |
| } | |
| allocator[loc] = new PointerType(); | |
| flags.set(loc); | |
| return allocator[loc]; | |
| } | |
| /*! \brief Returns the most recently initialized pointer. | |
| * Example usage: | |
| * Foo* ptr = arr.top(); | |
| * ptr->doSomething(); | |
| * @return a pointer to an object of PointerType. | |
| * | |
| */ | |
| int top() | |
| { | |
| for (int i = max-1; i >= 0; i--) | |
| { | |
| if (flags.test(i)) | |
| { | |
| return i; | |
| } | |
| } | |
| return 0; | |
| } | |
| /*! \brief Returns the location of first gap in the array. | |
| * Example usage: | |
| * int next = arr.gap(); | |
| * Foo* ptr = arr.alloc(next); | |
| * ptr->doSomething(); | |
| * @return an int between 0 and Max-1 | |
| */ | |
| int gap() | |
| { | |
| for (int i = 0; i < max; i++) | |
| { | |
| if (!flags.test(i)) | |
| { | |
| return i; | |
| } | |
| } | |
| return max-1; | |
| } | |
| /*! Retrieves the current stack size. | |
| * @return an integer between 0 and Max-1 | |
| */ | |
| int size() | |
| { | |
| return flags.count(); | |
| } | |
| /*! Retrieves a specific pointer from the array. If that pointer | |
| * has not yet been initialized, returns the most recently initialized pointer. | |
| * @return a pointer to a PointerType object. | |
| */ | |
| PointerType* dig(int location) | |
| { | |
| return allocator[location]; | |
| } | |
| /*! Removes a pointer from the stack by deleting it and decrementing | |
| * the stack count. If the stack is already at 0, it does nothing. | |
| * @return reference to this object for method chaining. (nodens.rem().alloc();) | |
| */ | |
| PtrArray& rem() | |
| { | |
| delete allocator[top()]; | |
| flags.set(top(), false); | |
| return *this; | |
| } | |
| }; | |
| }} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment