I'm not entirely sure where I'm going wrong here but I keep getting weird values for Push.
I don't know if my error is in Push itself or in the Display, but I assume it is in Push. Note that Push here is supposed to be similar to "std::deque::push_back".
Here is the related implementation code:
fsu::Queue <char> q;
q.Push('a');
q.Display(std::cout, '\0');
Here is what I get:
0x100100a20
0x100100a20
0x0
Related definitions:
void Push (const T& t); // push t onto queue
void Display (std::ostream& os, char ofc = '\0') const; // output contents
//through os
queue (); // default constructor
Queue (const Queue&); // copy constructor
~Queue (); // destructor
Queue& operator = (const Queue&); // assignment operator
private:
class Link
{
Link ( const T& t ); // 1-parameter constructor
T element_;
Link * nextLink_;
friend class Queue<T>;
};
Link * firstLink_;
Link * lastLink_;
void Copy (const Queue<T>& q);
static Link* NewLink(const T& t);
And here is what I have to for the implementation:
template < typename T >
fsu::Queue<T>::Queue () : firstLink_(0), lastLink_(0) // default constructor
{
//empty
}
template < typename T >
fsu::Queue<T>::Queue (const Queue& q) : firstLink_(0), lastLink_(0)
{
Copy(q);
}
template < typename T >
fsu::Queue<T>& fsu::Queue<T>::operator = (const Queue& q) // assignment operator
{
if (this != &q)
{
Clear();
Copy(q);
}
return *this;
}
template < typename T >
fsu::Queue<T>::Link::Link ( const T& t ) : element_(t), nextLink_(0) // 1-parameter constructor
{
};
template < typename T >
typename fsu::Queue<T>::Link* fsu::Queue<T>::NewLink (const T& t)
{
Link * newLink = new(std::nothrow) Link (t);
if (0 == newLink)
{
// exception handler
std::cerr << "** Queue error: memory allocation failure\n";
return 0;
}
return newLink;
}
template < typename T >
void fsu::Queue<T>::Copy (const Queue<T>& q)
{
if (firstLink_ != 0)
{
std::cerr << "** Error: Queue::Copy called by non-empty object\n";
// exit(EXIT_FAILURE);
}
if (q.firstLink_ == 0)
return;
Link* qlink = q.firstLink_;
while (qlink != 0)
{
Push(qlink -> element_);
qlink = qlink -> nextLink_;
}
}
template < typename T >
void fsu::Queue<T>::Push (const T& t) // push t onto queue
{
if (Empty())
{
Link * newLink = new Link(t);
newLink -> nextLink_ = NULL;
firstLink_ = newLink;
lastLink_ = newLink;
}
else
{
//to be implemented
}
}
template < typename T >
void fsu::Queue<T>::Display (std::ostream& os, char ofc) const // output contents
// through os
{
os << firstLink_ << std::endl;
os << lastLink_ << std::endl;
Link * currLink = firstLink_;
while (currLink)
{
currLink = currLink -> nextLink_;
os << currLink << std::endl;
}
}
os << firstLink_ << std::endl;
os << lastLink_ << std::endl;
Prints the addresses pointed to (i.e. the value the variable carries) rather than the item pointed to.
You must dereference the pointers! And then you get a Link structure, and from that you have to select the _element member, which you want to print:
os << (*firstLink_)._element << std::endl;
os << (*lastLink_).element << std::endl;
shorter and more common:
os << firstLink_->_element << std::endl;
os << lastLink_->_element << std::endl;
The need to explicitly dereference is a difference to, e.g. Java and C#, where references are "hidden" from the programmer and dealt with by the language. In C and C++, a pointer variable simply holds a memory address. You can manipulate memory addresses directly (google for "pointer arithmetic"); hence it is necessary to distinguish the pointer value (i.e. the address) from the value pointed to, which is located at this address.
Hope this is not too confusing.
Related
I need to build a sort of stack where I can push values on top:
5 // (size 1)
5 3 // (size 2)
5 3 8 // (size 3)
than remove them by value, such as removing 3:
5 8 // (size 2)
than be able to always get the last value (i.e. 8 in the example), when I need it).
I can push max 32 values, so I know the whole size (avoiding heap?).
I think to std::vector with:
initial reserve(32)
.push_back() for insert
vector.erase(std::remove(vector.begin(), vector.end(), value), vector.end()) for remove by value
vector[vector.size() - 1] to retrieve the last element
But maybe there are some stl container better for this kind of process? Not sure if vector are always in the stack and will do further memory reallocation under the hood...
You can write an allocator that contains your 32 values, and refuses to allocate any amount other than 32
template <typename T, std::size_t N = 32>
struct static_allocator
{
T* allocate(std::size_t n) { if (n != N) throw std::bad_alloc(); return arr; }
void deallocate(T *, std::size_t) {}
using pointer = T*;
using const_pointer = const T*;
using void_pointer = void*;
using const_void_pointer = const void*;
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
template <typename U>
struct rebind
{
using other = static_allocator<U, N>;
};
static_allocator select_on_container_copy_construction() { return {}; }
using propagate_on_container_copy_assignment = std::true_type;
using propagate_on_container_move_assignment = std::true_type;
using propagate_on_container_swap = std::true_type;
private:
T arr[N];
};
Then a std::vector<T, static_allocator<T>> will have it's elements as subobjects.
I don't think it's possible to avoid dynamic allocation and have sublinear random-access remove.
if size is limited to 32 elements
why not use a circular buffer of 32 elements, and roll the elements when they are 32 ?
There may be some bugs (don't use last() or remove () on an empty container, don't remove an element not inserted...) ,but it works for the functions you wanted. Here is the idea (heap is avoided)
#include <iostream>
template <typename T>
class Container {
public :
static const int smax_ = 32;
void erase () {
T* pt ((T*) val_);
for (int i (0); i != smax_; ++i, ++pt) *pt = 0;
size_ = 0;
}
Container () : size_ (0) { erase ();}
~Container () {}
void copy (const Container& c) {
size_ = c.size_;
T* pt ((T*) val_);
const T* qt ((const T*) c.val_);
for (int i (0); i != size_; ++i, ++pt, ++qt) *pt++ = *qt++;
}
Container (const Container& c) {
copy (c);
}
void push_back (const T& t) {
if (size_ == smax_) {
T* pt ((T*) val_);
const T* qt ((const T*) val_);
++qt;
for (int i (0); i != size_ -1; ++i, ++pt, ++qt) {
*pt = *qt;
}
*pt = t;
}
else {
val_ [size_] = t;
++size_;
}
}
int size () const {
return size_;
}
void remove (const T& t) {
if (!size_) return;
int i (0);
T* pt ((T*)val_);
while ((i < smax_) && (*pt != t)) {
++pt; ++i;
}
if (i != smax_) {
T* qt (pt);
++qt;
for (; i != size_ -1; ++i, ++pt, ++qt) {
*pt = *qt;
}
}
--size_;
}
void write (std::ostream& os) const {
const T* pt ((const T*) val_);
for (int i (0); i != size_; ++i, ++pt) os << *pt << " ";
}
bool operator == (const Container& c) const {
if (size_ != c.size_) return false;
const T* pt ((const T*) val_), *qt ((const T*) c.val_);
for (int i (0); i != size_; ++i, ++pt, ++qt) if (*pt != *qt) return false;
return true;
}
bool operator != (const Container& c) const {
return !operator == (c);
}
T& operator = (const Container& c) {
copy (c);
return *this;
}
T last () const {
return val_ [size_ -1];
}
T val_ [smax_];
int size_;
};
Test Program
int main (int argc, char* argv []) {
Container<int> c;
std::cout << "pushing back 5..." << std::endl;
c.push_back (5);
c.write (std::cout);
std::cout << std::endl;
std::cout << "c.last == " << c.last () << std::endl;
std::cout << "pushing back 3..." << std::endl;
c.push_back (3);
c.write (std::cout);
std::cout << std::endl;
std::cout << "c.last == " << c.last () << std::endl;
std::cout << "pushing back 8..." << std::endl;
c.push_back (8);
c.write (std::cout);
std::cout << std::endl;
std::cout << "c.last == " << c.last () << std::endl;
std::cout << "erasing 3..." << std::endl;
c.remove (3);
c.write (std::cout);
std::cout << std::endl;
std::cout << "c.last == " << c.last () << std::endl;
}
and the results :
pushing back 5...
5
c.last == 5
pushing back 3...
5 3
c.last == 3
pushing back 8...
5 3 8
c.last == 8
erasing 3...
5 8
c.last == 8
if you dont want memory reallocation then you can also use list container i.e linked list ..as it has mostly same properties to the vector..just it do not support random access or []operator ...else vector is perfect:)
For my Algorithm course project we can't use STL stuff like std::vector and so I'm trying to implement my own version of it (with templates).
It seems it works but when I declare a Vector< Vector< int > >
the .push() method starts to overwrite memory.
More specifically, with this code:
Vector<Vector<int>> v(3);
cout << v[0].push(0) << "\n";
cout << v[0].push(55) << "\n";
cout << v[0].push(4) << "\n";
cout << v[1].push(12) << "\n";
cout << v[1].push(3) << "\n";
cout << v[2].push(1) << "\n";
The output is this (.push() returns the address of where the element is inserted):
0x561328b0bc20
0x561328b0bc24
0x561328b0bc28
0x561328b0bc20
0x561328b0bc24
0x561328b0bc20
Any suggestion of why this happens?
Here is the code for my Vector class:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
template<class T>
class Vector {
private:
size_t _size;
size_t _capacity;
char* _buffer; //char* for performance
void _realloc(size_t);
public:
Vector(size_t s=0, T def=T());
T* push(T);
T& operator[](int);
size_t size() { return _size; }
};
template<class T>
void Vector<T>:: _realloc(size_t ncap)
{
_capacity = ncap;
char* nbuf = _buffer;
_buffer = new char[_capacity];
for(size_t i=0; i<_size * sizeof(T); ++i)
_buffer[i] = nbuf[i];
delete[] nbuf;
}
/*
* s -> size
* def -> default value
*/
template<class T>
Vector<T>:: Vector(size_t s, T def) : _size(s)
{
_capacity = 32;
while(_capacity < _size)
_capacity *= 2;
_buffer = new char[_capacity * sizeof(T)];
for(size_t i=0; i<_size; ++i)
((T*)_buffer)[i] = def;
}
/*
* check capacity, reallocs if necessary and push the element
* then return the addres (used only for debug)
*/
template<class T>
T* Vector<T>:: push(T ele)
{
if(_capacity == _size)
_realloc(2 * _capacity);
((T*)_buffer)[_size++] = ele;
return &((T*)_buffer)[_size-1];
}
template<class T>
T& Vector<T>:: operator[](int i)
{
if(i<0 or i>=(int)_size) {
cerr << "Out of bounds!\n";
abort();
}else
return ((T*)_buffer)[i];
}
template<class T>
ostream& operator<<(ostream& out, Vector<T>& v)
{
out << "{";
if(v.size() > 0) {
out << v[0];
for(size_t i=1; i<v.size(); ++i)
out << ", " << v[i];
}
out << "}";
return out;
}
Thanks!
PS: I know it's not a good use of C++ :P
Your operator= implicitly defined does the wrong thing. You use it in your constructor.
So, follow the rule of 0/3/5: Implement copy/move construtors/assignment and destructors, as this is an owning memory-management type. (Non-resource management types should follow the rule of 0; copyable resource management types the rule of 5.)
See rule of three. Implement all of destructor/copy constructor/move constructor/copy assign/move assign, or none of them.
Don't copy the data byte-wise when you realloc. std::move the Ts from the source to the dest.
In the copy construct/assign you'll want to copy the source Ts, not the underlying bytes.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm doing a custom Vector class for education purposes and I can't get the operator+ right. It triggers a breakpoint just after returning a value, but I don't know why, maybe the destructor or constructor, I don't know.
The rare part is, that when I change the operator+ to return T instead of Vector<T>, and returning thiscpy._els[i] the program runs fine. That's why I thought that the issue might be coming from constructor/destructor.
Anyways, here is the relevant part of Vector.h:
#include <initializer_list>
#include <functional>
typedef size_t SIZE;
template <class T>
class Vector {
private:
SIZE _sz;
T *_els;
public:
typedef std::function<void(Vector*)> sorting_function;
static const void populateVector(Vector*, const SIZE&, typename Vector<T>::sorting_function, const bool& sameLength = false);
Vector(SIZE sz = 0) : _sz(sz), _els(nullptr) {}
Vector(SIZE, const T&);
Vector(std::initializer_list<T>);
Vector(const Vector&);
Vector(Vector&& vec) : _sz(vec._sz), _els(vec._els) { delete[] vec._els; }
~Vector() { delete[] _els; }
Vector& operator=(const Vector&);
Vector& operator=(Vector&&);
Vector& operator=(std::initializer_list<T>);
Vector operator+(const Vector&);
SIZE size() const { return _sz; }
T* elems() const { return _els; }
int *begin() { return &_els[0]; } // for (auto i : Vector) {}
int *end() { return &_els[_sz]; } //
};
And here my relevant part Vector.cpp:
#include <stdexcept>
#include "Vector.h"
template <class T>
Vector<T>::Vector(const Vector& vec) {
cout << "Vector initializer" << endl;
if (this != &vec) {
populateVector(this, vec._sz, [&](Vector<T>* obj) {
for (SIZE i = 0; i < vec._sz; i++)
obj->_els[i] = vec._els[i];
});
}
}
template <class T>
Vector<T>& Vector<T>::operator=(const Vector<T>& vec)
{
cout << "Operator = const" << endl;
populateVector(this, vec._sz, [&](Vector<T>* obj) {
for (SIZE i = 0; i < vec._sz; i++)
obj->_els[i] = vec._els[i];
}, true);
return *this;
}
template <class T>
Vector<T>& Vector<T>::operator=(Vector<T>&& vec)
{
cout << "Operator = move" << endl;
populateVector(this, vec._sz, [&](Vector<T>* obj) {
for (SIZE i = 0; i < vec._sz; i++)
obj->_els[i] = vec._els[i];
});
delete[] vec._els;
return *this;
}
template <class T>
Vector<T>& Vector<T>::operator=(std::initializer_list<T> list)
{
populateVector(this, list.size(), [&](Vector<T>* obj) {
SIZE i = 0;
for (T elem : list)
obj->_els[i++] = elem;
});
return *this;
}
template <class T>
Vector<T> Vector<T>::operator+(const Vector<T>& vec)
{
cout << "Operator + const" << endl;
Vector<T> thiscpy(*this);
if (_sz != vec._sz) throw std::runtime_error("Vector size mismatch");
for (SIZE i = 0; i < _sz; i++)
thiscpy._els[i] += vec._els[i];
return thiscpy;
}
template <class T>
const void Vector<T>::populateVector(Vector<T>* obj, const SIZE& newsize, typename Vector<T>::sorting_function repopf, const bool& sameLength = false)
{
cout << "Pupulate vector" << endl;
if (sameLength && (obj->_sz != newsize)) throw std::runtime_error("Incompatible vector length");
obj->_sz = newsize;
try
{
if (obj->_els != nullptr) delete[] obj->_els;
obj->_els = new T[newsize];
repopf(obj);
}
catch (const std::exception& e)
{
obj->_sz = 0;
obj->_els = nullptr;
throw std::runtime_error("Couldn't populate vector");
}
}
And main.cpp:
int main() {
Vector<int> v1{ 1,2,3,4 }; //Vector<T>::Vector(std::initializer_list<T>);
Vector<int> v2{ 2,4,8,16 }; //Vector<T>::Vector(std::initializer_list<T>);
try
{
cout << "----------" << endl;
v1 + v2; //Triggers breakpoint
cout << "----------" << endl;
cout << "done" << endl;
}
catch (const std::exception& e)
{
cout << e.what() << endl;
}
cin.get();
return 0;
}
And the output of the program:
Pupulate vector
Pupulate vector
----------
Operator + const
Vector initializer
Pupulate vector
Your copy constructor never initializes els prior to calling populateVector, so it might not be nullptr (it also might be) and you're calling delete[] on whatever the content of the member pointer is. This can lead to undefined behavior.
Background
I have written a class Str that mimics string operations, for instructional purposes. The class Str is an array of characters in essence.
I created a function makeList that receives a Str object, creates a list of Str objects using push_back and returns the list.
I am using allocators, but I have tightened the memory management to allocate only enough memory for the characters created.
Problem
Compilation, linking, and run-time produce no errors.
The list object content is OK when viewed within MakeList using cout << ret.back().
The problem is that the objects within the list have garbage input overwriting the first ~10 characters when viewed in the main body.
I have also verified that the Str I create are being destroyed via the default destructor.
I have included the minimum amount of code to replicate the problem.
Non-class code:
list<Str> makeList(const Str s)
{
list<Str> ret;
ret.push_back(s);
cout << ret.back() << endl;
return ret;
}
int main() {
Str greeting = "Hello world";
list<Str> result;
result = makeList(greeting);
result.pop_front();
cout << "The result is " << result.front() << endl;
return 0;
}
Class code:
class Str {
friend std::istream& operator>>(istream&, Str&);
public:
typedef char* iterator;
typedef const char* const_iterator;
typedef size_t size_type;
typedef char value_type;
Str() { create(); } // default constructor
Str(const_iterator cp, const_iterator cp2) {
create(cp, cp2);
}
Str(const_iterator cp) {
create(cp, cp + strlen(cp));
}
~Str() {uncreate(); }
char& operator[](size_type i) { return data[i]; }
const char& operator[](size_type i) const { return data[i]; }
Str& operator=(const Str& s) {
uncreate();
create(s.begin(), s.end());
};
Str substr(size_type i, size_type d) const {
const_iterator cStart, cTerm;
cStart = this->begin() + i;
cTerm = this->begin() + i + d;
Str sub(cStart, cTerm);
cout << "Pointer diff = " << sub.limit - sub.data << endl;
return sub;
}
size_type size() const { return avail - data; }
iterator begin() { return data; }
const_iterator begin() const { return data; }
iterator end() { return avail; }
const_iterator end() const { return avail; }
private:
iterator data;
iterator avail;
iterator limit;
allocator<char> alloc;
void create();
void create(const_iterator, const_iterator);
void uncreate();
};
void Str::create()
{
data = avail = limit = 0;
}
void Str::create(const_iterator i, const_iterator j)
{
data = alloc.allocate(j - i);
limit = avail = uninitialized_copy(i, j, data);
}
void Str::uncreate()
{
if (data) {
iterator it = avail;
while (it != data)
alloc.destroy(--it);
alloc.deallocate(data, limit - data);
}
data = limit = avail = 0;
cout << "UNCREATED" << endl;
}
ostream& operator<<(ostream& os, const Str& s) {
for (Str::size_type i = 0; i != s.size(); i++)
os << s[i];
return os;
}
Among other things, you are missing a copy constructor for Str, but you do call it here :
result2 = makeList(greeting); // Pass by value -> copy
And here :
ret.push_back(s); // Pass by value -> copy
Without it, the default copy constructor is used, but it's not doing what you want.
Possible implementation :
Str(const Str& other)
{
create(other.begin(), other.end());
}
Always respect the rule of three
PART OF A HOMEWORK PROBLEM
I have a list of objects, and my goal is to try and find if an object X is present in that list (I am interested only in the first occurrence of that object). My code seems to work fine for the most part, but I have this strange error where the value of only 1 particular object is being modified after it is returned from a function.
I added 10 objects to the list with values 0 through 3. When I search for any number except 0, (./a.out 1 OR ./a.out 2 and so on)I get the right output. But when I search for 0(./a.out 0), the findInList() prints the correct result, but the main() prints the value 18 (which is not even present in the list).
I am attaching the full source code here in case someone wants to compile it and try it out. I am also attaching the gdb step through I did.
SOURCE:
#include <iostream>
#include <string>
#include <functional>
#include <list>
using namespace std;
class Page {
public:
int pgnum; // page number
union {
int lfu_count;
int lru_clock:1; // can only be 0/1
int lru_ref8:8; // we only need 8 bits
};
public:
// Constructors
Page(int num) { pgnum = num; }
Page() {}
// Operator overloading
bool operator== (const Page &p) const {
if(p.pgnum == pgnum)
return true;
else
return false;
}
bool operator!= (const Page &p) const {
return !(p==*this);
}
};
ostream & operator<<(ostream & os, const Page &p) {
os << "Page number: " << p.pgnum;
return os;
}
// Think of this as an equivalent to equals in Java (IT IS NOT, JUST IMAGINE)
struct PageNumber: public binary_function< Page, Page, bool > {
bool operator () ( const Page &p1, const Page &p2 ) const {
return p1 == p2;
}
};
// Function to find an object in any list given an Operation
template <class Operation, class T>
T* findInList( list<T> fullList, T obj, const Operation &op ) {
T* ret = NULL;
typename list<T>::iterator it = fullList.begin();
it = find_if( it, fullList.end(), bind2nd( op, obj ) );
if( it != fullList.end() ) {
cout << "Found obj in list: " << *it << endl;
ret = &(*it); // not the same as it (which is of type iterator)
}
return ret;
}
int main( int argc, char **argv ) {
Page page_to_find;
list<Page> frames;
if( argc != 2 ) {
cout << "Please enter 1 and only 1 argument" << endl;
exit(-1);
}
page_to_find.pgnum = atoi(argv[1]);
Page *p = new Page[10];
for( int i=0; i<10; i++ ) {
p[i].pgnum = i%4;
frames.push_back(p[i]);
}
list<Page>::iterator it_frames = frames.begin();
while( it_frames != frames.end() ) {
cout << "Page in frames: " << *it_frames << endl;
it_frames++;
}
Page* pg = findInList( frames, page_to_find, PageNumber() );
if( pg != NULL )
cout << "Found page: " << *pg << endl;
delete[] p;
return 0;
}
You're returning the address of an object in a list that is pushed into the parameter list by value. Thus it is undefined behavior. Consider changing the parameter of the list in findInList to a reference.
// note reference type change in parameter list.
template <class Operation, class T>
T* findInList( list<T>& fullList, T obj, const Operation &op ) {
T* ret = NULL;
typename list<T>::iterator it = fullList.begin();
it = find_if( it, fullList.end(), bind2nd( op, obj ) );
if( it != fullList.end() ) {
cout << "Found obj in list: " << *it << endl;
ret = &(*it); // not the same as it (which is of type iterator)
}
return ret;
}