C++ self made exception handling failure - c++

I am taking a c++ class and one of the tasks is the following:
they gave us a main program and we had to write the code behind it. Here is that code:
vector<int> iv(4);
iv[3]=42;
cout << iv[3] << endl; // prints "42"
try {
cout << iv[1] << endl; // throw exception
}
catch (vector<int>::Uninitialized&){
cout << "Uninitialized vector element!" << endl;
}
return 0;
I've come up with this code for the vector template:
T* data;
unsigned int size;
public:
class Uninitialized{};
explicit vector(int size) {
data = new T[size];
this -> size = size;
for (unsigned i = 0; i < size; i++) {
data[i] = 0;
}
}
~vector() {
delete [] data;
}
T& operator[](int index) {
if (index >= size) {
abort();
}
return data[index];
}
friend ostream& operator<< (ostream& o, const T& t) {
if (t == 0)
throw Uninitialized();
else
return o << t;
}
However, the friend method is never called, so the exception is never thrown.

You're throwing at
iv[3]=42;
because at that point, data[3] == 0.
Remember, even in your assignment you're calling operator[]; it doesn't care (or even know) if you want the T& for reading or writing.
You should approach this kind of problem (and, in general, problems where the code is simple enough and you know how to make the bug appear) by stepping through it with a debugger first. You would have caught this -- you'd immediately see that the exception isn't being thrown where you think it is.

When your code runs iv[3] = 0, which is outside the try .. catch, it will throw an exception because iv[3] is zero at that point.
You need to tell when an assignment has happened to an element. I suspect your best bet is to return a proxy class from operator [], which then has operators for assignment and converstion to T.

Related

C++ Dynamic Member Arrays Deleted Right Before Destructor Called

I'm working on an AI project and have started to implement a NeuralNetwork class. I just want to get something basic down so I used some malloc statements with some placement news and finally delete[]s.
However, once the NeuralNetwork object (created on the stack in the main function) is about to be deleted (I set a breakpoint at the start of the destructor), my arrays seem to have been prematurely deleted (value 0xcccccccc) and the delete[] statements therefore throw access violations.
Through further investigation I found out that this deleting happens right between the last Vector object being destructed and the start of the destructor of my NeuralNetwork object being called.
I made sure to implement both copy constructors and assignment operators to make sure no copying was taking place without me noticing.
I'm really baffled with this problem and hope that someone can catch my mistake. Source code will follow:
NeuralNetwork::NeuralNetwork(const std::initializer_list<size_t>& l):
m_size(l.size() - 1),
m_weights(static_cast<Matrix<double>*>(malloc(sizeof(Matrix<double>) * m_size))),
m_biases(static_cast<Vector<double>*>(malloc(sizeof(Vector<double>) * m_size)))
{
size_t index = 0;
auto itr = l.begin();
for (auto next = itr + 1; next != l.end(); ++next, ++itr, ++index)
{
new (m_weights + index) Matrix<double>(*next, *itr);
new (m_biases + index) Vector<double>(*next);
}
}
NeuralNetwork::NeuralNetwork(const NeuralNetwork& nn) :
m_size(nn.m_size),
m_weights(static_cast<Matrix<double>*>(malloc(sizeof(Matrix<double>)* m_size))),
m_biases(static_cast<Vector<double>*>(malloc(sizeof(Vector<double>)* m_size)))
{
for (size_t index = 0; index < m_size; ++index)
{
new (m_weights + index) Matrix<double>(nn.m_weights[index]);
new (m_biases + index) Vector<double>(nn.m_biases[index]);
}
}
NeuralNetwork::NeuralNetwork(NeuralNetwork&& nn) noexcept :
m_size(nn.m_size),
m_weights(nn.m_weights),
m_biases(nn.m_biases)
{
nn.m_size = 0;
nn.m_weights = nullptr;
nn.m_biases = nullptr;
}
NeuralNetwork::~NeuralNetwork()
{
delete[] m_weights; // exception thrown here, value is 0xcccccccc, nullptr
delete[] m_biases;
}
Main code:
int main()
{
NeuralNetwork nn{ 2, 1 };
Vector<double> input(2);
input.Get(0) = 0.5;
input.Get(1) = 0.25;
Vector<double> output = nn.Forward(input); // just does the math, nothing special
for (size_t i = 0; i < output.GetSize(); ++i)
std::cout << output.Get(i) << " ";
std::cout << std::endl;
}
In case any important source code is missing please let me know, thanks!
There is a big difference between malloc/free and new/delete and new[] / delete[]
malloc will allocate an unformated chunk of memory and free will free it
new will allocate and initialize that region and delete will call the destructor
sometimes it might work to use malloc and delete but it's a bad idea
new[] will also keep a few extra info before the the returned memory to know how many objects need to be deleted
Usefull links:
https://www.geeksforgeeks.org/placement-new-operator-cpp/
You should never write such code:
You should never have to use malloc/free in a C++ program.
Allocation and desallocation should match.
Dynamic memory allocation has surely more overhead that default initialization you try to avoid.
Your code would miserably failed if initializer list is empty.
Code has memory leaks.
If you define a copy constructor, then you should also define assignment operator (same for move constructor).
Standard library already do most relavant optimization. For example,, for a std::vector the constructor of an item will be only called when you call emplace_back.
You should really write standard code. It does not worth the trouble to write bugged code for marginal performance improvement.
Your class declaration should really look something like:
class NeuralNetwork
{
public:
NeuralNetwork(const std::initializer_list<size_t>& l);
// Other constructors as appropriate hereā€¦
private:
std::vector<Matrix<double>> m_weights;
std::vector<Vector<double>> m_biases;
};
And constructor should look similar to that (code not tested):
NeuralNetwork::NeuralNetwork(const std::initializer_list<size_t>& l):
{
if (l.empty()
{
// might assert in debug or throw an exception...
return;
}
m_weights.reserve(m_size);
m_biases.reserve(m_size);
auto itr = l.begin();
for (auto next = itr + 1; next != l.end(); ++next, ++itr, ++index)
{
m_weights.emplace(*next, *itr);
m_biases.emplace(*next);
}
}
Other constructors, assignment operators and destructors should be easier to implement, more robust and performance very similar.
As you are using C++11 features already, you can also use std::vector::emplace_back(), which will deal with placement new internally.
Example:
#include <iostream>
#include <initializer_list>
#include <vector>
template<class T> class Matrix {
public:
Matrix() {std::cout << "Matrix() " << this << std::endl;}
Matrix(int width,int height):w(width),h(height) {std::cout << "Matrix(" << w << "x" << h << ") " << this << std::endl;}
~Matrix() {std::cout << "Matrix(" << w << "x" << h << ") " << this << " goodbye" << std::endl;}
private:
int w,h;
};
class NN {
public:
NN()=default;
NN(const std::initializer_list<size_t> &l);
private:
std::vector<Matrix<double>> m_weights;
};
NN::NN(const std::initializer_list<size_t> &l) {
m_weights.reserve(l.size()-1); // or deal with move constructors
auto itr = l.begin();
for (auto next = itr + 1; next != l.end(); ++next, ++itr)
{
m_weights.emplace_back(*next, *itr);
}
}
int main() {
NN test{2,3,3,2};
return 0;
}
Output (from https://ideone.com/yHGAMc):
Matrix(3x2) 0x5638f59aae70
Matrix(3x3) 0x5638f59aae78
Matrix(2x3) 0x5638f59aae80
Matrix(3x2) 0x5638f59aae70 goodbye
Matrix(3x3) 0x5638f59aae78 goodbye
Matrix(2x3) 0x5638f59aae80 goodbye
So the default constructor was not involved and objects were destructed properly.

How to delete a dinamically allocated struct? (c++)

(About a hour ago I asked something about my code and accidentally deleted the post instead of editing it. I'm sorry for those who kindly answered to me. However, since I edited my code and partially fixed the issue, I'd rather ask for the new deal here.)
I have a class, and I have a struct inside my class. Since I want to be able to print its content, I overloaded the ostream operator:
struct packetarray {
const value_type *pktarr;
positive length;
packetarray() : pktarr(0), length(0) {}
packetarray(value_type *v, positive l) : pktarr(v), length(l) {}
~packetarray() {
delete[] pktarr;
pktarr = 0;
length = 0;
}
friend std::ostream &operator<<(std::ostream &os, const packetarray &p) {
os << "[ ";
for (int j = 0; j < p.length; ++j) {
os << p.pktarr[j];
if (j < (p.length - 1)) {
os << ",\t";
}
}
os << " ]";
return os;
}
};
with value_type being typedef T for my template class.
I have a method, packet, which returns a packetarray object:
packetarray* packet(positive y, positive x) {
try {
if (y >= this->y || x >= this->x) {
throw OutOfBounds();
}
value_type *v = new value_type[this->z];
for (int z = 0; z < this->z; z++) {
v[z] = this->operator()(z, y, x);
}
packetarray *p = new packetarray(v, this->z);
v = 0;
return p;
}
catch (const OutOfBounds &e) {
std::cout << e.message() << std::endl;
packetarray *p = new packetarray();
return p;
}
}
As you can see, when I write value_type *v = new value_type[this->z] I allocate memory on the heap, memory which is later supposed to be freed. However, since this memory is shared with the pktarr pointer of my packetarray struct, I can't free the memory unti I safely returned (and printed) the content of my packetarray object.
My intention (expectation?) was to delete that part of memory in the packetarray destructor -- but even if I actually create a packetarray object on the heap by writing packetarray *p = new packetarray(v, this->z), no destructor is being called at the end of the program. So, how am I supposed to free the memory I need to allocate in order to initialize my packetarray object?
(For those who are wondering what my class does: it's basically a 3-dimentional array and the packet method returns a data structure which contains all the elements at a certain (y, x) position for every plane z.)

std::vector segfaulting instead of throwing exception

I am attempting to create a container class for a std::vector, to teach myself a bit more about templates, overloading operators, and managing exceptions.
For the moment, I'm just defining the basic operations. I have a template class listed below; I've overloaded the += and [] operators to push_back the vector with a T and access the elements of the vector directly, respectively. This works as expected.
The += operator does what it's supposed to do, and attempting to use the [] operator on an element out of range will throw the exception as intended.
Here is the prototype class and implementation as it currently stands:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <class T>
class Inventory
{
public:
void operator += (const T& b) { backpack.push_back(b); }
T operator [] (const unsigned& b)
{
if (backpack.empty() || backpack.size() < b)
throw string("Out of Range");
return backpack[b];
}
void operator -= (const unsigned& b)
{
if (backpack.empty() || backpack.size() < b)
throw string("No such element exists.");
backpack.erase(backpack.begin() + b);
}
private:
vector<int> backpack;
};
int main()
{
Inventory<int> pack;
pack += 2;
pack += 4;
try
{
cout << "It was " << pack[0] << endl;
cout << "It was " << pack[1] << endl;
pack -= 0;
cout << "It is now " << pack[0] << endl;
//pack -= 1; // Segfaults?
}
catch (string e)
{
cout << "Error: " << e << endl;
}
}
The issue is with the -= operator, intended to erase an element at the indicated position on the right hand side. When I stay within the boundaries of the vector, this works as intended; however, I do not get an exception if I specify an out of bounds number to erase; I get a seg-fault instead. I have attempted to determine the exact point the segfault occurs by adding additional print commands:
void operator -= (const unsigned& b)
{
cout << "In Overload!\n";
if (backpack.empty() || backpack.size() < b)
{
cout << "Exception!\n";
throw string("No such element exists.");
}
backpack.erase(backpack.begin() + b);
}
The "Exception!" line is never reached. The program faults before it can reach that point, even though I should be evaluating for undefined behavior. I believe I'm missing a key component in understanding how this process works. Is there a way I should be writing this so it can throw instead of fault?
Compiling using g++ -std=c++17 -Wall -Wextra -pedantic on Linux x64 architecture.
Your error checking is off by 1.
if (backpack.empty() || backpack.size() < b)
If the std::vector backpack contains only two values, backpack.size() is going to be 2, and backpack will contain backpack[0] and backpack[1].
Unfortunately, if the index b gets passed in as 2, this code will still attempt to access backpack[2], resulting in undefined behavior.
In fact, the entire if statement can be simply rewritten as:
if (b >= backpack.size())
throw string("Out of Range");
You have an "off by one" error in your code.,
Consider what happens if the array is not empty and b == backpack.size() in the code.
if (backpack.empty() || backpack.size() < b)
throw string("Out of Range");
return backpack[b];
In this case, valid indices for elements of backpack are 0 through to backpack.size() - 1.
If b == backpack.size(), the code will NOT throw an exception, and WILL attempt to return backpack[backpack.size()] which gives undefined behaviour.
One possible symptom of undefined behaviour is a "segfault".
One way to avoid the problem is to change the test to backpack.size() <= b.
Another alternative is to take advantage of std::vector::at() which will throw a std::out_of_range exception on an out-of-bounds index:
T operator [] (const unsigned& b)
{
try
{
return backpack.at(b);
}
catch (std::out_of_range& e)
{
throw string("Out of Range");
}
}
void operator -= (const unsigned& b)
{
try
{
backpack.at(b);
backpack.erase(backpack.begin() + b);
}
catch(std::out_of_range& e)
{
throw std::string("No such element exists.");
}
}
Live Example

Even the Copy Assignment Operator can't assist

Kindly help me figure out where the issue is. I have followed the rule of three as well and made several modifications to the code.
#include <iostream>
using namespace std;
class AStack {
public:
AStack();
AStack(int);
AStack(const AStack&);
~AStack();
AStack& operator = (const AStack& s);
void push(int);
int pop();
int top();
bool isEmpty();
void flush();
private:
int capacity ;
int* a;
int index = -1; // Index of the top most element
};
AStack::AStack() {
a = new int[25];
capacity = 25;
}
AStack::AStack(int size) {
a = new int[size];
capacity = size;
}
AStack::AStack(const AStack& s) {
capacity = s.capacity;
delete[] a; // To avoid memory leak
a = new int[capacity];
for (int i = 0; i < capacity; i++) {
a[i] = s.a[i];
}
index = s.index;
}
AStack::~AStack() {
delete[] a;
}
AStack& AStack::operator = (const AStack& s) {
capacity = s.capacity;
delete[] a; // To avoid memory leak
int* a = new int[capacity];
for (int i = 0; i < capacity; i++) {
a[i] = s.a[i];
}
index = s.index;
return *this;
}
void AStack::push(int x) {
if (index == capacity - 1) {
cout << "\n\nThe stack is full. Couldn't insert " << x << "\n\n";
return;
}
a[++index] = x;
}
int AStack::pop() {
if (index == -1) {
cout << "\n\nNo elements to pop\n\n";
return -1;
}
return a[index--];
}
int AStack::top() {
if (index == -1) {
cout << "\n\nNo elements in the Stack\n\n";
return -1;
}
return a[index];
}
bool AStack::isEmpty() {
return (index == -1);
}
void AStack::flush() {
if (index == -1) {
cout << "\n\nNo elements in the Stack to flush\n\n";
return;
}
cout << "\n\nFlushing the Stack: ";
while (index != -1) {
cout << a[index--] << " ";
}
cout << endl << endl;
}
AStack& reverseStack(AStack& s1) {
AStack s2;
while (!s1.isEmpty()) {
s2.push(s1.pop());
}
s1 = s2;
return s1;
}
int main() {
AStack s1;
s1.push(1);
s1.push(2);
s1.push(3);
s1.push(4);
s1.push(5);
s1 = reverseStack(s1);
cout << "\n\nFlushing s1:\n";
s1.flush();
system("pause");
return 0;
}
I fail to understand how even after defining the appropriate copy assignment operator, the values in s1 after returning from the function are garbage values.
If your copy constructor is correct, and your destructor is correct, your assignment operator could be written in a much easier and safer fashion.
Currently, your assignment operator has two major flaws:
No check for self-assignment.
Changing the state of this before you know you can successfully allocate the
memory (your code is not exception safe).
The reason for your error is that the call to reverseStack returns a reference to the current object. This invoked the assignment operator, thus your assignment operator was assigning the current object to the current object. Thus issue 1 above gets triggered.
You delete yourself, and then you reallocate yourself, but where did you get the values from in the loop to assign? They were deleted, thus they're garbage.
For item 2 above, these lines change this before you allocate memory:
capacity = s.capacity;
delete[] a; // To avoid memory leak
What happens if the call to new[] throws an exception? You've messed up your object by not only changing the capacity value, but you've also destroyed your data in the object by calling delete[] prematurely.
The other issue (which needs to be fixed to use the copy/swap idiom later in the answer), is that your copy constructor is deallocating memory it never allocated:
AStack::AStack(const AStack& s) {
capacity = s.capacity;
delete[] a; // ?? What
Remove the line with the delete[] a, since you are more than likely calling delete[] on a pointer that's pointing to garbage.
Now, to rid you of these issues with the assignment operator, the copy/swap idiom should be used. This requires a working copy constructor and a working destructor before you can utilize this method. That's why we needed to fix your copy constructor first before proceeding.
#include <algorithm>
//...
AStack& AStack::operator = (AStack s)
{
std::swap(capacity, s.capacity);
std::swap(a, s.a);
std::swap(index, s.index);
return *this;
}
Note that we do not need to check for self assignment, as the object that is passed by value is a brand new, temporary object that we are taking the values from, and never the current object's values (again, this is the reason for your original code to fail).
Also, if new[] threw an exception, it would have been thrown on the call to the assignment operator when creating the temporary object that is passed by value. Thus we never get the chance to inadvertently mess up our object because of new[] throwing an exception.
Please read up on what the copy/swap idiom is, and why this is the easiest, safest, and robust way to write an assignment operator. This answer explains in detail what you need to know:
What is the copy-and-swap idiom?
Here is a live example of the fixed code. Note that there are other changes, such as removing the default constructor and making the Attack(int) destructor take a default parameter of 25.
Live Example: http://ideone.com/KbA20D

C++: Program crash while adding object to custom vector class

I'm working on an email validation program for my cmpsci class and am having trouble with this one part.
What I'm doing is reading a list of valid top level domains from a text file into a vector class I wrote myself (I have to use a custom vector class unfortunately). The problem is that the program reads in and adds the first few domains to the vector all well and fine, but then crashes when it gets to the "org" line. I'm completely stumped why it works for the first few and then crashes.
Also, I have to use a custom string class; that's why I have the weird getline function (so I get the input in a char* for my String constructor). I've tried using the standard string class with this function and it still crashed in the same way so I can rule out the source of the problem being my string class. The whole program is quite large so I am only posting the most relevant parts. Let me know if more code is needed please. Any help would be awesome since I have no clue where to go from here. Thanks!
The ReadTlds function:
void Tld::ReadTlds() {
// Load the TLD's into the vector
validTlds = Vector<String>(0); // Init vector; declaration from header file: "static Vector<String>validTlds;"
ifstream in(TLD_FILE);
while(!in.eof()) {
char tmpInput[MAX_TLD_LENGTH]; // MAX_TLD_LENGTH equals 30
in.getline(tmpInput, MAX_TLD_LENGTH);
validTlds.Add(String(tmpInput)); // Crashes here!
}
}
My custom vector class:
#pragma once
#include <sstream>
#define INIT_CAPACITY 100
#define CAPACITY_BOOST 100
template<typename T> class Vector {
public:
// Default constructor
Vector() {
Data=NULL;
size=0;
capacity=INIT_CAPACITY;
}
// Init constructor
Vector(int Capacity) : size(0), capacity(Capacity) {
Data = new T[capacity];
}
// Destructor
~Vector() {
size=0;
Data = NULL;
delete[] Data;
}
// Accessors
int GetSize() const {return size;}
T* GetData() {return Data;}
void SetSize(const int size) {this->size = size;}
// Functions
void Add(const T& newElement) {
Insert(newElement, size);
}
void Insert(const T& newElement, int index) {
// Check if index is in bounds
if((index<0) || (index>capacity)) {
std::stringstream err;
err << "Vector::Insert(): Index " << index << " out of bounds (0-" << capacity-1 << ")";
throw err.str();
}
// Check capacity
if(size>=capacity)
Grow();
// Move all elements right of index to the right
for(int i=size-1; i>=index; i--)
Data[i+1]=Data[i];
// Put the new element at the specified index
Data[index] = newElement;
size++;
}
void Remove(int index) {
// Check if index is in bounds
if((index<0) || (index>capacity-1)) {
std::stringstream err;
err << "Vector::Remove():Index " << index << " out of bounds (0-" << capacity-1 << ")";
throw err.str();
}
// Move all elements right of index to the left
for(int i=index+1; i<size; i++)
Data[i-1]=Data[i];
}
// Index operator
T& operator [] (int index) const {
// Check if index is in bounds
if((index<0) || (index>capacity-1)) {
std::stringstream err;
err << "Vector operator[]:Index " << index << " out of bounds (0-" << capacity-1 << ")";
throw err.str();
}
return Data[index];
}
// Assignment oper
Vector<T>& operator = (const Vector<T>& right) {
Data = new T[right.GetSize()];
for(int i=0; i<right.GetSize(); i++)
Data[i] = right[i];
size = right.GetSize();
return *this;
}
private:
T *Data;
int size; // Current vector size
int capacity; // Max size of vector
void Grow() {
capacity+=CAPACITY_BOOST;
T* newData = new T[capacity];
for(int i=0; i<capacity; i++)
newData[i] = Data[i];
// Dispose old array
Data = NULL;
delete[] Data;
// Assign new array to the old array's variable
Data = newData;
}
};
The input file:
aero
asia
biz
cat
com
coop
edu
gov
info
int
jobs
mil
mobi
museum
name
net
org <-- crashes when this line is read
pro
tel
travel
The error Visual Studio throws is:
Unhandled exception at 0x5fb04013 (msvcp100d.dll) in Email4.exe: 0xC0000005: Access violation reading location 0xabababbb.
The problem is in your grow function:
void Grow() {
capacity+=CAPACITY_BOOST;
T* newData = new T[capacity];
for(int i=0; i<capacity; i++)
newData[i] = Data[i];
You increase the capacity, but then copy elements that didn't exist in the old array. It should be something like:
void Grow() {
int old_capacity = capacity;
capacity+=CAPACITY_BOOST;
T* newData = new T[capacity];
for(int i=0; i<old_capacity; i++)
newData[i] = Data[i];
You also NULL out Data before deleting it in both Grow and the destructor, which causes a memory leak. In both cases, you really don't need to set it to NULL at all, since there's no change of it being accidentally double-deleted (in Grow it's set to a new pointer immediately, in the destructor the object's lifetime is over). So just
delete[] Data;
alone is fine.
Also I think
if(size>=capacity)
can be:
if(size == capacity)
since size should never be over capacity. That would mean you'd already overflowed the buffer.
Matthew is probably right. Still, there's a valuable lesson to be learned here.
When you hit a problem like this, don't stop walking your code in your ReadTlds function. Keep walking inside the Vector class. Functions like Insert and Grow probably hold the error, but if you don't walk through them, you'll never find it.
Debugging is it's own very special skill. It takes a long time to get it down pat.
edit it's a late night and I misread your code, but I left my post to comment back
Also in the default ctor you do
Data = NULL;
capacity=INIT_CAPACITY;
(EDIT: expanded explanation here)
But never allocate the memory for Data. Shouldn't it be:
Vector() {
Data= new T[INIT_CAPCITY];
size=0;
capacity=INIT_CAPACITY;
}
And remove is missing
--size
EDIT:
Fellow readers help me out here:
Data is of type T* but everywhere else you are assigning and allocating it just like T instead of T* . My C++ days are too long gone to remember whether using a T& actually resolves this.
Also I can't remember that if you have an array of pointers and destruct it, that the dtor for the single instances in the array are destroyed.
Also in the assignment operator, wouldn't you be copying the pinters? so you just have to rely on the fact the the instance where you copyid from is never deleted (because then your objects would be dead too).
hth Mario