Weird Error with Hashtable Code for Assignment(Maybe Compiler Bug)
nick
xerofoify@gmail.com
Sat Nov 12 07:04:00 GMT 2016
On 2016-11-12 01:37 AM, Andrew Pinski wrote:
> On Fri, Nov 11, 2016 at 10:30 PM, nick <xerofoify@gmail.com> wrote:
>> Greetings Gcc Folks,
>> Either this is me doing something very simple in a school assignment for creating a basic hashtable
>> or a compiler bug. I am currently seeing this error during my tables run on copy constructor call during
>> the tester and have set to find out why it doesn't work. After some googling it seems either I am doing
>> string pointer to string swaps.
>
> This should have gone to gcc-help@ rather than here. This mailing
> list is more for the automated emails from bugzilla.
>
> Anyways I think the problem is you assume:
> new Record*[N];
>
> Will NULL out the array. It does not.
>
> Thanks,
> Andrew
>
>
Ok I will move it there but makes no sense at least from my understanding of C++. Shouldn't new overwrite that memory
with a null block or is new so stupid that it doesn't do this so I actually new to do this instead:
new Record*[N]():
Thanks,
Nick
>> or it's a compiler bug. This is the error I am getting after running in gdb with backtrace:
>> Program received signal SIGSEGV, Segmentation fault.
>> 0x00007ffff7b769bb in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ()
>> from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
>> (gdb) backtrace
>> #0 0x00007ffff7b769bb in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ()
>> from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
>> #1 0x00000000004067f6 in HashTable<int>::Record::getKey() const ()
>> #2 0x00000000004060ee in HashTable<int>::HashTable(HashTable<int> const&) ()
>> #3 0x0000000000403cab in main ()
>> This is the complete code for the project:
>> #include <string>
>> #include <utility>
>> #include<iostream>
>> using namespace std;
>> /*The functions I updated for Simple Table are
>> 1.search
>> 2.grow
>> 3.update
>> 4.Both Copy Constructor and Copy Assignment
>> 5.Destructor
>> */
>> template <class TYPE>
>> class Table {
>> public:
>> Table() {}
>> virtual bool update(const string& key, const TYPE& value) = 0;
>> virtual bool remove(const string& key) = 0;
>> virtual bool find(const string& key, TYPE& value) = 0;
>> virtual ~Table() {}
>> };
>>
>> template <class TYPE>
>> class SimpleTable :public Table<TYPE> {
>>
>> struct Record {
>> TYPE data_;
>> string key_;
>> Record(const string& key, const TYPE& data) {
>> key_ = key;
>> data_ = data;
>> }
>>
>> };
>>
>> Record** records_; //the table
>> int max_; //capacity of the array
>> int size_; //current number of records held
>> int search(const string& key);
>> void sort();
>> void grow();
>> public:
>> SimpleTable(int maxExpected);
>> SimpleTable(const SimpleTable& other);
>> SimpleTable(SimpleTable&& other);
>> virtual int numRecords();
>> virtual bool isEmpty();
>> virtual bool update(const string& key, const TYPE& value);
>> virtual bool remove(const string& key);
>> virtual bool find(const string& key, TYPE& value);
>> virtual const SimpleTable& operator=(const SimpleTable& other);
>> virtual const SimpleTable& operator=(SimpleTable&& other);
>> virtual ~SimpleTable();
>> };
>>
>>
>> //returns index of where key is found.
>> template <class TYPE>
>> int SimpleTable<TYPE>::search(const string& key) {
>> int rc = -1;
>> for (int i = 0; i<size_; i++) {
>> if (records_[i]->key_ == key) {
>> rc = i;
>> break;
>> }
>> }
>> return rc;
>> }
>> //checks if array is empty
>> template <class TYPE>
>> bool SimpleTable<TYPE>::isEmpty(){
>> return size_==0;
>> }
>> template <class TYPE>
>> //return size of array
>> int SimpleTable<TYPE>::numRecords(){
>> return size_;
>> }
>> //sort the according to key in table
>> template <class TYPE>
>> void SimpleTable<TYPE>::sort() {
>> int minIdx = 0;
>> for (int i = 0; i<size_; i++) {
>> minIdx = i;
>> for (int j = i + 1; j<size_; j++) {
>> if (records_[j]->key_ < records_[minIdx]->key_) {
>> minIdx = j;
>> }
>> }
>> Record* tmp = records_[i];
>> records_[i] = records_[minIdx];
>> records_[minIdx] = tmp;
>> }
>> }
>>
>> //grow the array by one element
>> template <class TYPE>
>> void SimpleTable<TYPE>::grow() {
>> Record** newArray = new Record*[max_ + 1];
>> max_ = max_ + 1;
>> for (int i = 0; i<size_; i++) {
>> newArray[i] = records_[i];
>> }
>> records_ = std::move(newArray);
>> }
>>
>> /* none of the code in the function definitions below are correct. You can replace what you need
>> */
>> template <class TYPE>
>> SimpleTable<TYPE>::SimpleTable(int maxExpected) : Table<TYPE>() {
>> records_ = new Record*[maxExpected];
>> max_ = maxExpected;
>> size_ = 0;
>> }
>>
>> template <class TYPE>
>> SimpleTable<TYPE>::SimpleTable(const SimpleTable<TYPE>& other) {
>> records_ = new Record*[other.max_];
>> max_ = other.max_;
>> size_ = 0;
>> for (int i = 0; i<other.size_; i++) {
>> update(other.records_[i]->key_, other.records_[i]->data_);
>> }
>> }
>> template <class TYPE>
>> SimpleTable<TYPE>::SimpleTable(SimpleTable<TYPE>&& other) {
>> size_ = swap(other.size_);
>> max_ = swap(other.max_);
>> records_ = swap(other.records_);
>> }
>>
>> template <class TYPE>
>> bool SimpleTable<TYPE>::update(const string& key, const TYPE& value) {
>> int idx = search(key);
>> if (idx == -1) {
>> if (size_ == max_) {
>> grow();
>> }
>> records_[size_++] = new Record(key, value);
>> for(int i=0;i<size_;i++) {
>> if(records_[i]->key_ > records_[size_-1]->key_) {
>> Record* tmp = records_[i];
>> records_[i] = records_[size_-1];
>> records_[i] = tmp;
>> }
>> }
>> }
>> else {
>> records_[idx]->data_ = value;
>> }
>> return true;
>> }
>> template <class TYPE>
>> bool SimpleTable<TYPE>::remove(const string& key) {
>> int idx;
>> idx=search(key);
>> if(idx!=-1){
>> delete records_[idx];
>> for(int i=idx;i<size_-1;i++){
>> records_[i]=records_[i+1];
>> }
>> size_--;
>> return true;
>> } else {
>> return false;
>> }
>> }
>> template <class TYPE>
>> bool SimpleTable<TYPE>::find(const string& key, TYPE& value) {
>> int idx = search(key);
>> if (idx == -1) {
>> return false;
>> } else {
>> value = records_[idx]->data_;
>> return true;
>> }
>> }
>>
>> template <class TYPE>
>> const SimpleTable<TYPE>& SimpleTable<TYPE>::operator=(const SimpleTable<TYPE>& other) {
>> if (this != &other) {
>> if(records_){
>> delete[] records_;
>> }
>> records_ = new Record*[other.max_];
>> max_ = other.max_;
>> size_ = 0;
>> for (int i = 0; i<other.size_; i++) {
>> update(other.records_[i]->key_, other.records_[i]->data_);
>> }
>>
>> }
>> return *this;
>> }
>> template <class TYPE>
>> const SimpleTable<TYPE>& SimpleTable<TYPE>::operator=(SimpleTable<TYPE>&& other) {
>> swap(records_, other.records_);
>> swap(size_, other.size_);
>> swap(max_, other.max_);
>> return *this;
>> }
>> template <class TYPE>
>> SimpleTable<TYPE>::~SimpleTable() {
>> if (records_) {
>> int sz=size_;
>> for(int i=0;i<sz;i++){
>> remove(records_[0]->key_);
>> }
>> }
>> }
>>
>> template <class TYPE>
>> class HashTable :public Table<TYPE> {
>> // This is the internal structure for array elements for hastable
>> struct Record {
>> TYPE data_; // data per array element
>> string key_;//key to lookup for data element
>> Record* next_; // next record to create linkly linked list for bucketing
>> // Constructor to set values of Record
>> Record(const string key, const TYPE data) {
>> key_ = key;
>> data_ = data;
>> next_=nullptr;
>> }
>> //empty Constructor that sets values to empty safe state
>> Record(){
>> key_="";
>> data_=0;
>> next_=nullptr;
>> }
>> //Returns key of Record
>> string getKey() const {
>> return key_;
>> }
>> //Sets key of Record
>> string setKey(string key) {
>> key_=key;
>> }
>> //Returns data member of Record
>> TYPE getData() const {
>> return data_;
>> }
>> //Sets data member of Record
>> void setData(TYPE data) {
>> data_=data;
>> }
>> //Gets next element in linked list for bucketing
>> Record *getNext() const {
>> return next_;
>> }
>> //Sets next element in linked list for bucketing
>> void setNext(Record *next) {
>> next_ = next;
>> }
>>
>> };
>>
>> Record** table_; //the table
>> int size_;//size_
>> int cap;//max number of records allowed in table
>> std::hash<std::string> hash;//hash function used
>>
>> public:
>> HashTable(int maxExpected);
>> HashTable(const HashTable& other);
>> HashTable(HashTable&& other);
>> int numRecords();
>> bool isEmpty();
>> virtual bool update(const string& key, const TYPE& value);
>> virtual bool remove(const string& key);
>> virtual bool find(const string& key, TYPE& value);
>> virtual const HashTable& operator=(const HashTable& other);
>> virtual const HashTable& operator=(HashTable&& other);
>> virtual ~HashTable();
>> };
>> /* none of the code in the function definitions below are correct. You can replace what you need
>> */
>> //returns size of table
>> template <class TYPE>
>> int HashTable<TYPE>::numRecords() {
>> return size_;
>> }
>> //returns if hashtable has no records been inserted
>> template <class TYPE>
>> bool HashTable<TYPE>::isEmpty(){
>> return size_==0;
>> }
>> //Constructor that allocates memory equal to passed amount in maxExpected and sets hashtable to empty state
>> template <class TYPE>
>> HashTable<TYPE>::HashTable(int maxExpected) : Table<TYPE>() {
>> int size_=0;
>> table_=new Record*[maxExpected]();
>> cap=maxExpected;
>> }
>> //Copy Constructor that creates a copy of passed hashtable as argument to create a new copy of including memory allocations
>> template <class TYPE>
>> HashTable<TYPE>::HashTable(const HashTable<TYPE>& other) {
>> table_ = new Record*[other.cap];
>> size_=other.size_;
>> hash = other.hash;
>> cap=other.cap;
>> for(int i=0;i<cap;i++){
>> if(other.table_==nullptr){
>> continue;
>> }
>> string key=other.table_[i]->getKey();
>> table_[i]->key_=key;
>> TYPE data=other.table_[i]->getData();
>> table_[i]->setData(data);
>> }
>> }
>> //Move constructor that moves the hashtable passed into the current table being constructed
>> template <class TYPE>
>> HashTable<TYPE>::HashTable(HashTable<TYPE>&& other) {
>> swap(size_,other.size_);
>> swap(cap,other.cap);
>> swap(table_,other.records_);
>> swap(hash,other.hash);
>> }
>> //Updates record with the string passed to the new data for the record's data element and returns true if found/updated otherwise false
>> template <class TYPE>
>> bool HashTable<TYPE>::update(const string& key, const TYPE& value) {
>> int hashvalue=hash(key)%cap;
>> Record* prev=nullptr;
>> Record* entry=table_[hashvalue];
>>
>> while (entry != nullptr && entry->getKey() != key) {
>> prev=entry;
>> entry=entry->getNext();
>> }
>>
>> if (entry == nullptr) {
>> entry = new Record(key, value);
>> if (prev == nullptr) {
>> // insert as first bucket
>> table_[hashvalue] = entry;
>> } else {
>> prev->setNext(entry);
>> }
>> } else {
>> // just update the value
>> entry->setData(value);
>> }
>> size_++;
>> return true;
>> }
>> //Removes the record with the string passed for the key value and returns true if removed otherwise false if not found
>> template <class TYPE>
>> bool HashTable<TYPE>::remove(const string& key) {
>> int hashValue = hash(key)%cap;
>> Record *prev = nullptr;
>> Record *entry = table_[hashValue];
>>
>> while (entry != nullptr && entry->getKey() != key) {
>> prev = entry;
>> entry = entry->getNext();
>> }
>>
>> if (entry == nullptr) {
>> // key not found
>> return false;
>> }
>> else {
>> if (prev == nullptr) {
>> // remove first bucket of the list
>> table_[hashValue] = entry->getNext();
>> } else {
>> prev->setNext(entry->getNext());
>> }
>> delete entry;
>> }
>> size_--;
>> return true;
>> }
>> //Finds value in table and updates with the value passed if found returns true otherwise false
>> template <class TYPE>
>> bool HashTable<TYPE>::find(const string& key, TYPE& value) {
>> int hashValue = hash(key)%cap;
>> Record* entry =table_[hashValue];
>> while (entry != nullptr) {
>> if (entry->getKey() == key) {
>> value=entry->getData();
>> return true;
>> }
>> entry = entry->getNext();
>> }
>> return false;
>> }
>> //Copy Assignment Operator creates copy of hashtable passed into current hashtable
>> template <class TYPE>
>> const HashTable<TYPE>&HashTable<TYPE>::operator=(const HashTable<TYPE>& other) {
>> if (table_) {
>> delete[] table_;
>> }
>> table_ = new Record*[other.cap];
>> size_=other.size_;
>> hash = other.hash;
>> cap=other.cap;
>> for(int i=0;i<cap;i++){
>> if(other.table_==nullptr){
>> continue;
>> }
>> string key=other.table_[i]->getKey();
>> table_[i]->key_=key;
>> TYPE data=other.table_[i]->getData();
>> table_[i]->setData(data);
>> }
>> return *this;
>> ;
>>
>> }
>> //Moves Assignment Operator which moves passed hashtable into current hashtable
>> template <class TYPE>
>> const HashTable<TYPE>& HashTable<TYPE>::operator=(HashTable<TYPE>&& other) {
>> swap(size_,other.size_);
>> swap(table_,other.table_);
>> swap(hash,other.hash);
>> swap(cap,other.cap);
>> return *this;
>>
>> }
>> //Destructor this destroys the hashtable when it goes out of scope or is called directly
>> template <class TYPE>
>> HashTable<TYPE>::~HashTable() {
>> // destroy all buckets one by one
>> for (int i = 0; i < cap; ++i) {
>> Record *entry = table_[i];
>> while (entry != nullptr) {
>> Record *prev = entry;
>> entry = entry->getNext();
>> delete prev;
>> }
>> table_[i] = nullptr;
>> }
>> // destroy the hash table
>> delete [] table_;
>> }
>> G++ Version/Toolchain used as with gcc -v:
>> Using built-in specs.
>> COLLECT_GCC=/usr/bin/g++
>> COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
>> Target: x86_64-linux-gnu
>> Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.4' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
>> Thread model: posix
>> gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
>> Huge Thanks for any help,
>> Nick
More information about the Gcc-help
mailing list