I keep getting a segmentation fault and am not sure why. Pretty new to templates and am just messing around trying to figure things out. I built a stack using a template, and have only incorporated the member functions push and top/peek so far. Trying to create a string stack.
#include <iostream>
#include <string>
template <class T>
class TemplateStack {
public:
typedef T type;
TemplateStack()//Default Constructor taking no parameters
{
max_size_ = 50;
TopOfStack = 0;
}
void push(T element)
{
if (TopOfStack == max_size_)
throw string("Stack's underlying storage is overflow");
TopOfStack++;
data_[TopOfStack] = element;
}
T top() {
if (TopOfStack == -1)
throw string("Stack is empty");
return data_[TopOfStack];
}
private:
size_t TopOfStack; //Generic data type for the top element of stack
size_t max_size_;
T* data_;
};
int Main (){
TemplateStack <string> T;
T.push("Hello");
T.push("World!");
std::cout<<T.top()<<std::endl;
return 0;
};
You did not allocate memory for the data member
T* data_;
in the constructor
TemplateStack()//Default Constructor taking no parameters
{
max_size_ = 50;
TopOfStack = 0;
}
So any operation with the stack that uses the pointer results in undefined behavior.
And the initial value of the data member TopOfStack according to the implementation of other methods shall be -1.
I think you mean at least
TemplateStack()//Default Constructor taking no parameters
{
max_size_ = 50;
TopOfStack = -1;
data_ = new T[max_size];
}
If so you need also to write a destructor to free allocated memory.
And the method push shall check another condition
void push(T element)
{
if (TopOfStack + 1 == max_size_)
throw string("Stack's underlying storage is overflow");
TopOfStack++;
data_[TopOfStack] = element;
}
Or as the data member TopOfStack has the type size_t then you could write
TemplateStack()//Default Constructor taking no parameters
{
max_size_ = 50;
TopOfStack = 0;
data_ = new T[max_size];
}
void push(T element)
{
if (TopOfStack == max_size_)
throw string("Stack's underlying storage is overflow");
data_[TopOfStack++] = element;
}
and
T top() {
if (TopOfStack == 0)
throw string("Stack is empty");
return data_[TopOfStack -1];
}
Related
I'm having trouble figuring out the destructor for my hashTable class, the destructor is like this:
template <typename ElementType>
HashSet<ElementType>::~HashSet() noexcept
{
for (unsigned int i=0;i<hashCapacity;i++)
{
Node* current = hashTable[i];
while(current != nullptr)
{
Node* entry = current;
current = current->next;
delete[] entry;
}
}
delete[] hashTable;
}
No matter I use either delete[] or delete, it gives me either double-free errors or segmentation fault.
The class template is below:
template <typename ElementType>
class HashSet : public Set<ElementType>
{
public:
// The default capacity of the HashSet before anything has been
// added to it.
static constexpr unsigned int DEFAULT_CAPACITY = 10;
// A HashFunction is a function that takes a reference to a const
// ElementType and returns an unsigned int.
using HashFunction = std::function<unsigned int(const ElementType&)>;
public:
// Initializes a HashSet to be empty so that it will use the given
// hash function whenever it needs to hash an element.
explicit HashSet(HashFunction hashFunction);
// Cleans up the HashSet so that it leaks no memory.
~HashSet() noexcept override;
// add() adds an element to the set. If the element is already in the set,
// this function has no effect. This function triggers a resizing of the
// array when the ratio of size to capacity would exceed 0.8, in which case
// the new capacity should be determined by this formula:
//
// capacity * 2 + 1
//
// In the case where the array is resized, this function runs in linear
// time (with respect to the number of elements, assuming a good hash
// function); otherwise, it runs in constant time (again, assuming a good
// hash function). The amortized running time is also constant.
void add(const ElementType& element) override;
Where my add function and default constructor implementation is like this:
template <typename ElementType>
HashSet<ElementType>::HashSet(HashFunction hashFunction)
: hashFunction{hashFunction}
{
hashCapacity = DEFAULT_CAPACITY;
hashSize = 0;
hashTable = new Node* [hashCapacity];
for (int i=0;i<hashCapacity;++i)
{
hashTable[i] = nullptr;
}
}
template <typename ElementType>
void HashSet<ElementType>::add(const ElementType& element)
{
if (contains(element)==false)
{
if ((hashSize/hashCapacity) > 0.8)
{
}
else
{
unsigned int index = hashFunction(element) % hashCapacity;
hashSize += 1;
Node* add = new Node;
add->next = nullptr;
add->value = element;
if (hashTable[index]==nullptr)
{
hashTable[index] = add;
}
else
{
Node* addNode = hashTable[index];
while(addNode->next != nullptr)
{
addNode = addNode->next;
}
addNode->next = add;
}
}
}
}
Note: that resize hashtable part is incomplete because I'm examining the functionality for my hash table to hold a small amount of value first.
I am trying to implement a circular buffer that utilizes mutex in order to be thread safe. I have been using the following code:
#include <cstdio>
#include <memory>
#include <mutex>
template <class T>
class circular_buffer {
public:
explicit circular_buffer(size_t size) :
buf_(std::unique_ptr<T[]>(new T[size])),
max_size_(size)
{
}
void put(T item)
{
std::lock_guard<std::mutex> lock(mutex_);
buf_[head_] = item;
if (full_)
{
tail_ = (tail_ + 1) % max_size_;
}
head_ = (head_ + 1) % max_size_;
full_ = head_ == tail_;
}
T get()
{
std::lock_guard<std::mutex> lock(mutex_);
if (empty())
{
return T();
}
//Read data and advance the tail (we now have a free space)
auto val = buf_[tail_];
full_ = false;
tail_ = (tail_ + 1) % max_size_;
return val;
}
void reset()
{
std::lock_guard<std::mutex> lock(mutex_);
head_ = tail_;
full_ = false;
}
bool empty() const
{
//if head and tail are equal, we are empty
return (!full_ && (head_ == tail_));
}
bool full() const
{
//If tail is ahead the head by 1, we are full
return full_;
}
size_t capacity() const
{
return max_size_;
}
size_t size() const
{
size_t size = max_size_;
if (!full_)
{
if (head_ >= tail_)
{
size = head_ - tail_;
}
else
{
size = max_size_ + head_ - tail_;
}
}
return size;
}
private:
std::mutex mutex_;
std::unique_ptr<T[]> buf_;
size_t head_ = 0;
size_t tail_ = 0;
const size_t max_size_;
bool full_ = 0;
};
The problem with this code is that I cannot seem to get it to work with arrays of floats. I am getting a function returns array error (from the get function). I am not entirely sure how to fix this (tried passing in an array and using get() function to point that array, but this didn't work either). Sorry if this question is a bit abstract, I am honestly completely in over my head on this one (first job as dev and literally my 6 days into job they're having me make a very complex radar mapping app). Let me know if you need any clarifications on anything.
edit: Thanks everyone! Michael's answer worked, and thanks for the suggestions. I honestly feel like I'm drowning over my head right now so all the tips are extremely helpful!
First of all, be aware that if anyone uses the size(), empty(), or full() methods of an instance of this class template while someone else is concurrently using get(), put(), or reset(), you will end up with undefined behavior. size() or empty() will also have to lock the mutex because they read the values of objects (full_, head_, and tail_) that may potentially be modified concurrently. Apart from that, it would seem to me that put() always writes something, even if the queue is full. That's probably not what one would typically want.
Based on your description, I assume the problem you're asking about has to do with trying to create, e.g., a circular_buffer<float[4]>. Think about what the get() method would turn into if you substitute the type float[4] for T:
float get()[4] { … }
You end up with a function returning an array. Functions are not allowed to return arrays [dcl.fct]/11.* That's why you end up with a compiler error as soon as you'd call the get() method on such a circular_buffer. Use, e.g., std::array instead: circular_buffer<std::array<float, 4>>.
*) I believe this is most likely for historical reasons. The way array types were designed to behave when passed to functions in C was such that arrays would effectively end up being passed by reference; there is no good way for a function to return an array by reference, and returning by value would be inconsistent with how they are passed in. Thus, it's probably best to just disallow arrays to be returned at all…
I would like to ask 2 question about this code. Where I just try to simulate a stack.
Stack.h
#pragma once
namespace stackandqueue {
class Stack
{
private:
int index;
int *stackdata;
public:
Stack();
~Stack();
void push(int val);
int pop();
int top();
bool isEmpty();
};
}
Stack.cpp
#include "stdafx.h"
#include "Stack.h"
namespace stackandqueue {
Stack::Stack() : index{ 0 }
{
stackdata = new int[index];
}
Stack::~Stack()
{
delete[] &stackdata;
}
void Stack::push(int val) {
stackdata[index] = val;
index++;
}
int Stack::pop() {
int val = stackdata[index];
index--;
return val;
}
int Stack::top() {
return stackdata[index];
}
bool Stack::isEmpty() {
return index == 0;
}
}
Meaning is to let me create
Stack stack;
And then it initilizes a dynamic array with 0 as first index and that let me push, pop, top values.
First question:
Why am I having unresolved symbols for method definitions?
Second question:
About 'stackdata', you find is the right way if I want to declare an "array" with dynamic size for this behaviour?
I'm open for improvements and best practices. Im used to programming languagesbut I've never delved into c ++ and I don't want to have bad practices. So you see I am taking it from the begining.
Thanks.
I post solution reached with your help that maybe helps someone.
class Stack
{
private:
int index;
int* stackdata;
public:
Stack(int size);
~Stack();
void push(int val);
int pop();
int top();
bool isEmpty();
};
Stack::Stack(int size)
: index {0}, stackdata{new int[size]}
{
}
Stack::~Stack()
{
delete[] stackdata;
}
void Stack::push(int val) {
stackdata[index] = val;
index++;
}
int Stack::pop() {
index--;
return stackdata[index];
}
int Stack::top() {
return stackdata[index-1];
}
bool Stack::isEmpty() {
return index == 0;
}
There are several problems with this.
An array, dynamically allocated or otherwise, is not a stack/queue/vector. You're creating literally 0 ints. All of your element accesses after that have undefined behaviour. You need your array to grow, i.e. be a vector, e.g. std::vector.
delete[] &stackdata has the wrong level of indirection. You meant delete[] stackdata. You were trying to delete the pointer which was not dynamically allocated.
You're missing copy/move constructors and copy/move assignment operators so as soon as you transport a Stack anywhere it will explode. (The original instance will do a delete[] on the same pointer that the copied/moved instances will!) Read about the rule of three/five/zero.
Other than that, it looks like a stack.
The problem you don't have here is an undefined reference, which is funny because that's the only one you asked about. :) If you do indeed have such a thing, it's likely a problem with your build system (failing to compile that source file), which we cannot see.
I am having trouble coding Copy constructor for C++ HashTable. Now below is the class structure
template <class TYPE>
class HashTable : public Table<TYPE>
{
struct Record
{
TYPE data_;
string key_;
Record* Next;
Record(const string& key, const TYPE& data)
{
key_ = key;
data_ = data;
Next = nullptr;
}
Record(const Record& a) {
if(!a.key_.empty()){
if(a.Next == nullptr){
Next = nullptr;
}
else
{
Record* temp = a.Next ;
Record *temp2 = Next;
while(temp != nullptr)
{
temp2 = temp ;
temp = temp->Next ;
}
temp2->Next = nullptr;
}
data_ = a.data_ ;
key_ = a.data_ ;
} // user-
};
int TableSize;
Record** records;
}
};
and below is the copy constructor
template
HashTable<TYPE>::HashTable(const HashTable<TYPE>& other)
{
records = new Record*[other.TableSize];
TableSize = other.TableSize;
for(int i = 0 ; i < other.TableSize; i++)
records[i]= (new Record(*other.records[i]));
}
I have also posted the code on ideone http://ideone.com/PocMTD. The code for copy constructor seems to be crashing. I don't see any memory leak that will cause the program to crash. I have tried memcopy, using the insert function and the all seems to fail.
Replace int TableSize; and Record** records; with std::vector<std::unique_ptr<Record>>
In Record, change Record* Next; to Record* Next=nullptr;.
Stop calling new.
Include HashTable(HashTable&&)=default;.
HashTable<TYPE>::HashTable(const HashTable<TYPE>& other)
{
records.reserve( other.records.size() );
for (auto const& rec_in : other.records)
records.emplace_back( new Record(*rec_in) ); // make_shared<Record> in C++14
}
Now we are no longer doing manual memory management. So an entire set of worries is gone.
Next, look at that raw Next pointer. It is bad news. When you copy a Record, the Next pointer points into the old set of Record structures.
We can fix this in a few ways. The slickest is to use an offset pointer.
template<class T>
struct offset_ptr {
std::ptrdiff_t offset = std::numeric_limits<std::ptrdiff_t>::max();
explicit operator bool()const {
return offset!=std::numeric_limits<std::ptrdiff_t>::max();
}
T* get() const {
return (T*)( offset+(char*)this );
}
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
operator T*() const { return get(); }
offset_ptr(std::nullptr_t):offset_ptr() {}
explicit offset_ptr(T* p) {
if (!p) return;
offset = (char*)p-(char*)this;
Assert(*this);
}
offset_ptr()=default;
offset_ptr(offset_ptr const&)=default;
offset_ptr& operator=(offset_ptr const&)=default;
offset_ptr(offset_ptr&&)=default;
offset_ptr& operator=(offset_ptr&&)=default;
};
which instead of storing a pointer by absolute location, stores an offset.
Now we do this:
template<class TYPE> struct Table{};
template <class TYPE>
class HashTable :public Table<TYPE>
{
public:
struct Record
{
TYPE data_;
std::string key_;
offset_ptr<Record> Next;
Record(const std::string& key, const TYPE& data)
{
key_ = key;
data_ = data;
Next = nullptr;
}
Record(const Record& a)
{
if(!a.key_.empty())
{
if(a.Next == nullptr)
{
Next = nullptr;
}
else
{
auto temp = a.Next;
while(temp != nullptr)
{
Next = temp;
temp = temp->Next;
}
}
data_ = a.data_;
key_ = a.data_;
}
}
};
std::vector<Record> records;
};
and no copy ctor is needed; the offset ptr knows the location of the other record as an offset within the records. Data is stored by-value instead of by-reference.
Note that we have a vector of Records, not pointers-to-Records. This is key for the offset_ptr to work. Resizing isn't a problem, as the offsets remain the same. Copying remains safe, as offsets on each side now refer to other elements within their vector. Inserting/removing in the middle is dangerous, but simply nulling elements is not.
Note that buffers of size max std::ptrdiff_t or beyond are not supported by the above offset_ptr. On a 64 bit system that is about 2 gigs; on a 64 bit system it is large. (I don't use 0 for the null value, because if I did then an offset_ptr<X> as the first member of a struct X would nullify if I ever made it point to its enclosing X.)
boost also has a less bespoke offset_ptr type. The implementation above is meant as a sketch of how easy it is, not a solid implementation.
You do not show the complete code here (neither on ideone), but let me take a guess based on what I see.
I assume that your other object, which you pass in the copy c'tor has a fully set up list of Records.
I further assume that your HashTable class has a destructor (not shown) which deletes all the linked Records.
Your copy constructor calls the copy c'tor of Record(for each entry in the array of pointers to Record). The Record coyp c'tor only makes a shallow copy, i.e. only the pointer to the next element is copied (it will still point to the next element of the copied Record from the other hash table.
Thus, when other and its copy are deleted (at the end of scope or program; not shown), you will have double deletion (crash).
Fix: Make sure that Record has correct copy constructor, copy assignment and destructor (maybe even move c'tor and move assignment) (rule of five).
The same applies for the HashTable class as well.
Better fix: Use std::unordered_map.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I am working on a linked list implementation of a stack of ItemType (currently set to double but can be changed) values. Although my code is compiling fine, I have realized that my size method is rather inefficient, as it uses iteration to obtain the size of linked list--O(n) time complexity--when it could simply store size as a field of node, update it within my other methods, then return that value--improving the method so it has O(1) time complexity. Unfortunately, however, I am having some issues figuring out how to integrate this new size field, particularly how to initialize its value, and my compiler keeps telling me it is unable to be edited. My question, then, is how can I implement size as a field of the node class (or should I implement it somewhere else?) and where in my code should I initialize and update it?
Below is my header file for the linked list stack:
#ifndef DBLSTACK_H
#define DBLSTACK_H
typedef double ItemType; // stack currently holds doubles
class DblStack
{
private:
//Node class
class Node
{
public:
double data;
Node *next;
// Node constructor
Node(double value, Node * link = 0)
{
data = value;
next = link;
}
};
typedef Node * NodePtr;
// Data members
NodePtr myTop; //points to top of stack
public:
// Class Constructor
DblStack();
// Copy Constructor
DblStack(const DblStack& rhs);
// Class Deconstructor
~DblStack();
// Assignment operator
// Assigns a stack to another
const DblStack& operator= (const DblStack& rhs);
// isEmpty
// Checks if the stack is empty
bool isEmpty() const;
// push
// Pushes an item on top of the stack.
void push(const ItemType& item);
// pop
// Pops the top item off the stack.
void pop();
// top
// Returns the top item of the stack without popping it.
ItemType top() const;
// size
// Returns the number of items on the stack.
size_t size() const;
};
#endif
And here is my source file:
#include <cstddef> //for NULL
#include <stdexcept>
#include "DblStack.h"
using namespace std;
// Class Constructor
DblStack::DblStack()
: myTop(0)
{
}
// Copy Constructor
DblStack::DblStack(const DblStack& rhs)
{
myTop = 0;
if (!rhs.isEmpty())
{
// Copy first node
myTop = new DblStack::Node(rhs.top());
// Set pointers to run through stack
DblStack::NodePtr lastPtr = myTop;
DblStack::NodePtr origPtr = rhs.myTop->next;
while (origPtr != 0)
{
lastPtr->next = new DblStack::Node(origPtr->data);
lastPtr = lastPtr->next;
origPtr = origPtr->next;
}
}
}
// Class Deconstructor
DblStack::~DblStack()
{
// Set pointers to run through stack
DblStack::NodePtr curr = myTop, next;
while (curr != 0)
{
next = curr->next;
delete curr;
curr = next;
}
}
// Assignment operator
// Assigns a stack to another
const DblStack& DblStack::operator= (const DblStack& rhs)
{
if (this != &rhs)
{
this->~DblStack();
if (rhs.isEmpty())
{
myTop = 0;
}
else
{
DblStack tmp(rhs); // Call copy constructor
std::swap(myTop, tmp.myTop);
}
}
return *this;
}
// isEmpty
// Checks if the stack is empty
bool DblStack::isEmpty() const
{
return (myTop == 0);
}
// push
// Pushes an item on top of the stack.
void DblStack::push(const ItemType& item)
{
myTop = new DblStack::Node(item, myTop);
}
// pop
// Pops the top item off the stack.
void DblStack::pop()
{
if (!isEmpty())
{
DblStack::NodePtr ptr = myTop;
myTop = myTop->next;
delete ptr;
}
else
{
throw std::underflow_error("Stack is empty");
}
}
// top
// Returns the top item of the stack without popping it.
ItemType DblStack::top() const
{
if (!isEmpty())
{
return myTop->data;
}
else
{
throw std::underflow_error("Stack is empty");
}
}
// size
// Returns the number of items on the stack.
size_t DblStack::size() const
{
size_t size = 0;
DblStack::NodePtr ptr;
for (ptr = myTop; ptr != 0; ptr = ptr->next)
{
size++;
}
return size;
}
While improving my size method is the main goal of this question, I'd also appreciate any other suggestions you may have for optimizing my code. Thank you!
You'll want to add a size member variable to your DblStack class:
class DblStack
{
private:
size_t size;
// ...
}
When you first construct a DblStack, it has nothing it in, so its size should be 0:
DblStack::DblStack()
: myTop(0)
, size(0)
{ }
Now you need to think about when the size will change! You should find that the only cases it changes are when items are either pushed or popped from the stack. Consequently, you'll want your push and pop methods to reflect this:
// Push increases stack size
size++;
// Pop decreases stack size
size--;
Lastly, you can change your size() method to just return the size:
size_t size() const { return size; }
Include size as a member of DblStack, and modify its other methods to keep it up to date.