C++: Template class binary operator overloading - seg fault? - c++

The following describe the example I have which works:
header:
const size_t N = 10;
// template<size_t N>
class SymbolicMonomial {
public:
int powers[N];
int constant;
SymbolicMonomial() {
for (int i = 0; i < N; i++) {
this->powers[i] = 0;
}
this->constant = 1;
}
SymbolicMonomial(int variable): SymbolicMonomial(){
this->powers[variable] = 1;
}
static SymbolicMonomial as_monomial(int value){
auto result = SymbolicMonomial();
result.constant = value;
return result;
}
bool is_constant(){
for(int i=0;i<N;i++){
if(this->powers[i] > 0){
return false;
}
}
return true;
}
};
// template<size_t N>
std::ostream &operator<<(std::ostream &out, const SymbolicMonomial value){
out << value.constant << "(";
for(int i=0;i<N-1;i++){
out << value.powers[i] << ", ";
}
out << value.powers[N-1] << ")";
}
// template<size_t N>
SymbolicMonomial operator*(SymbolicMonomial lhs, SymbolicMonomial rhs) {
SymbolicMonomial result = SymbolicMonomial();
for (int i = 0; i < N; i++) {
result.powers[i] = lhs.powers[i] + rhs.powers[i];
}
result.constant = lhs.constant * rhs.constant;
return result;
}
The main.cpp:
int main(int argc, char *argv[])
{
auto t_a = symbolic::SymbolicMonomial(2);
auto t_b = symbolic::SymbolicMonomial(1);
auto t_c = t_b*t_a*t_a;
std::cout << t_c << std::endl;
return 0;
}
And everything is fine. However, I wanted to change the whole thing to have a template argument <N> instead of a constant. Thus this is the templated code:
header.h:
template<const size_t N>
class SymbolicMonomial {
public:
int powers[N];
int constant;
SymbolicMonomial() {
for (int i = 0; i < N; i++) {
this->powers[i] = 0;
}
this->constant = 1;
}
SymbolicMonomial(int variable): SymbolicMonomial(){
this->powers[variable] = 1;
}
static SymbolicMonomial as_monomial(int value){
auto result = SymbolicMonomial<N>();
result.constant = value;
return result;
}
bool is_constant(){
for(int i=0;i<N;i++){
if(this->powers[i] > 0){
return false;
}
}
return true;
}
};
template<const size_t N>
std::ostream &operator<<(std::ostream &out, const SymbolicMonomial<N> value){
out << value.constant << "(";
for(int i=0;i<N-1;i++){
out << value.powers[i] << ", ";
}
out << value.powers[N-1] << ")";
}
template<const size_t N>
SymbolicMonomial<N> operator*(SymbolicMonomial<N> lhs, SymbolicMonomial<N> rhs) {
SymbolicMonomial<N> result = SymbolicMonomial<N>();
for (int i = 0; i < N; i++) {
result.powers[i] = lhs.powers[i] + rhs.powers[i];
}
result.constant = lhs.constant * rhs.constant;
return result;
}
And main.cpp:
int main(int argc, char *argv[])
{
auto t_a = symbolic::SymbolicMonomial<10>(2);
auto t_b = symbolic::SymbolicMonomial<10>(1);
auto t_c = t_b*t_a*t_a;
std::cout << t_c << std::endl;
return 0;
}
Now the non template version works as expected, however the templated one fails with code 139 (SEGFAULT). Firstly, I do not understand why the code fails if someone can explain and secondly how to fix it?

std::ostream &operator<<(std::ostream &out, const SymbolicMonomial<N> value) isn't returning a value. For me, in Visual Studio, that resulted in a compile error. Adding return out; to the end of the function lead to the code working without an ACCESS_VIOLATION (Windows flavor of a SEGFAULT).
All of your bound-checking looks correct, so, if I had to guess, I'd say that your compiler is ignoring the missing return, and you're entering a spooky space known as undefined behavior when you work with a return value that was never actually set.
Assuming you're using GCC, you can set -Werror=return-type to throw compile errors when you make these kinds of mistakes.

Related

How do I cast a typename variable parameter as a string

The problem: I am trying to create a function capable of finding the largest number if the array is an integer, double, float, etc. If the array given is a string it returns the string in the string with the most letters. However, I don't know how to cast list [0] and list[i] as strings.
#include <isostream>
#include <algorithm>
using namespace std;
unsigned int strlength(string word) {
char *ch = &word[0];
unsigned int count = 0;
while (*ch != '\0') {
count++;
ch++;
}
return *count;
}
template<typename U>
U maxNumber(U list[], int size) {
unsigned int i;
if (typeid(list) == typeid(string*)) {
unsigned int i;
for (i = 0; i < size; i++) {
if (strlength(list[0]) < strlength(list[i])) {
list[0] = list[i];
}
else {
list[0] = list[0];
}
}
return list[0];
}
else {
for (i = 0; i < size; i++) {
if (list[0] < list[i]) {
list[0] = list[i];
}
else {
continue;
}
}
return list[0];
}
}
if (typeid(list) == typeid(string*)) is the wrong tool.
You need compile time branch,
either with if constexpr
template<typename U>
U maxNumber(U list[], int size) {
if constexpr (std::is_same_v<U, std::string>) {
auto less_by_size = [](const auto& lhs, const auto rhs){
return lhs.size() < rhs.size(); };
return *std::max_element(list, list + size, less_by_size);
} else {
return *std::max_element(list, list + size);
}
}
or via overload/tag dispatching
std::string maxNumber(std::string list[], int size) {
auto less_by_size = [](const auto& lhs, const auto rhs){
return lhs.size() < rhs.size(); };
return *std::max_element(list, list + size, less_by_size);
}
template<typename U>
U maxNumber(U list[], int size) {
return *std::max_element(list, list + size);
}

C++ class objects copy constructor and operator=

I'm currently building a library In C++. I have met this problem few days ago and I'm unable to fix it. I have shorten the code so it can be seen easier.
Below is my code:
class String
{
private:
mutable char* v;
mutable int l = 0;
public:
String()
{
l++;
v = new char[1];
*v = '\0';
}
String(const char* value)
{
int length = 0;
while (value[length])
length++;
l = length + 1;
v = new char[l];
for (int i = 0; i < length; i++)
v[i] = value[i];
v[l - 1] = '\0';
}
String(const String& value)
{
int length = value.len();
l = length + 1;
v = new char[l];
for (int i = 0; i < length; i++)
v[i] = value[i];
v[l - 1] = '\0';
}
int len() const
{
return l - 1;
}
char* val() const
{
return v;
}
char* operator=(const char* value) const
{
delete[] v;
int length = 0;
while (value[length])
length++;
l = length + 1;
v = new char[l];
for (int i = 0; i < length; i++)
v[i] = value[i];
v[l - 1] = '\0';
return v;
}
char* operator=(const String& value) const
{
delete[] v;
int length = value.len();
l = length + 1;
v = new char[l];
for (int i = 0; i < length; i++)
v[i] = value[i];
v[l - 1] = '\0';
return v;
}
char operator[](const int& index) const
{
return v[index];
}
};
class StringArray
{
private:
union ArrayDef
{
public:
mutable String stringV;
mutable int intV;
ArrayDef()
{
}
ArrayDef(const String& value)
: stringV(value)
{
}
ArrayDef(const int& value)
: intV(value)
{
}
ArrayDef(const ArrayDef& value)
{
intV = value.intV;
stringV = value.stringV;
}
String operator=(const String& value) const
{
stringV = value;
return stringV;
}
int operator=(const int& value) const
{
intV = value;
return intV;
}
ArrayDef operator=(const ArrayDef& value)
{
intV = value.intV;
stringV = value.stringV;
return *this;
}
};
mutable ArrayDef* arrdef;
mutable int arrLen = 0;
public:
StringArray()
{
}
void add(const ArrayDef& value) const
{
ArrayDef temp[arrLen + 1];
for (int i = 0; i < arrLen; i++)
temp[i] = arrdef[i];
temp[arrLen] = value;
arrLen++;
delete[] arrdef;
arrdef = new ArrayDef[arrLen];
for (int i = 0; i < arrLen; i++)
arrdef[i] = temp[i];
}
int len() const
{
return arrLen;
}
ArrayDef val(const int& index) const
{
return arrdef[index];
}
};
And my driver code:
#include <iostream>
int main()
{
StringArray arr;
arr.add(String("Hello"));
arr.add(String("World"));
std::cout << "Length of the array: " << arr.len() << std::endl;
int indexOfString = 1;
int indexOfCharacter = 2;
char s = arr.val(indexOfString).stringV[indexOfCharacter];
std::cout << "arr[" << indexOfString << "][" << indexOfCharacter << "]: " << s << std::endl;
}
I have created two class, that is, String and StringArray class.
For String class, I need to always add a null character after the char pointer array for safety issue.
For StringArray class, I uses union because it's actually an array for multiple types.
It can be successfully compiled but it output some random character and it is different every time I run it.
Any answers will be appreciated, and please tell me why and how it don't works. Thank you.
From,
HaiQin.
This code is just a collection of antipatters that makes it difficult to study. What is the reason of making the internal data mutable? Why do you need to play with length and l where sometimes it is the length of the string, sometimes it is the size of array? The operator operator= returns char* which is a bad practice. Using const int& index as a parameter is a strange choice. You allocate arrays multiple times but you have no destructor that frees the memory.
Here your assignment operator returns a value, not reference!
ArrayDef operator=(const ArrayDef& value)
{
intV = value.intV;
stringV = value.stringV;
return *this;
}
Next comes even more dangerous practice:
// Recollect that this is a union
ArrayDef(const ArrayDef& value)
{
intV = value.intV;
stringV = value.stringV;
}
You are assigning both fields of the union at the same time! Did you mean struct?
Try to fix that. Start with changing union to structure.
One of the things that certainly will not work is the ArrayDef copy constructor and operator=(const ArrayDef & value). This is because you may only use the active value in the union, not both at the same time. This is usually solved by using a tagged union. Is there a reason you cannot use the Standard Template Library?
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> arr;
arr.push_back(std::string("Hello"));
arr.push_back(std::string("World"));
std::cout << "Length of the array: " << arr.size() << std::endl;
constexpr int indexOfString = 1; // second string - starting from 0!
constexpr int indexOfCharacter = 2; // third character
char s = arr.at(indexOfString).c_str()[indexOfCharacter]; // using interfaces closest to the original
std::cout << "arr[" << indexOfString << "][" << indexOfCharacter << "]: " << s << std::endl;
}

Binary '[': no operator found which takes a left hand operand of type 'const SortableVector<int>'

So I ran into this issue as I was coding for the class I'm currently in, I believe the code should run fine but this came up: Binary '[': no operator found which takes a left hand operand of type 'const SortableVector'
I'm not quite sure how to tackle this, any suggestions?
I ended up looking at No '==' operator found which takes a left-hand operand of const Type to see if I could find a solution in there however I did not, it seems my issue is stemming from something that I don't personally see.
#include <iostream>
#include "SortableVector.h"
using namespace std;
int main() {
const int SIZE = 10;
SortableVector<int> intTable(SIZE);
for (int x = 0; x < SIZE; x++) {
int z;
cout << "Please enter a number with no decimals: ";
cin >> z;
intTable[x] = z;
}
cout << "These values are in intTable:\n";
intTable.print();
intTable.sortInt(intTable, SIZE);
cout << "These values in intTable are now sorted: ";
intTable.print();
return 0;
}
//SortableVector.h
#include <iostream>
#include <cstdlib>
#include <memory>
#include <vector>
using namespace std;
struct IndexOutOfRangeException {
const int index;
IndexOutOfRangeException(int ix) : index(ix) {}
};
template<class T>
class SortableVector {
unique_ptr<T[]> aptr;
int vectorSize;
public:
SortableVector(int);
SortableVector(const SortableVector &);
int size() const { return vectorSize; }
T &operator[](int);
void sortInt(SortableVector<int>, int);
void print() const;
};
template<class T>
SortableVector<T>::SortableVector(int s) {
vectorSize = s;
aptr = make_unique<T[]>(s);
for (int count = 0; count < vectorSize; count++) {
aptr[count] = T();
}
}
template<class T>
SortableVector<T>::SortableVector(const SortableVector &obj) {
vectorSize = obj.vectorSize;
aptr = make_unique<T[]>(obj.vectorSize);
for (int count = 0; count < vectorSize; count++) {
aptr[count] = obj[count];
}
}
template<class T>
T &SortableVector<T>::operator[](int sub) {
if (sub < 0 || sub >= vectorSize) {
throw IndexOutOfRangeException(sub);
return aptr[sub];
}
}
template<class T>
void SortableVector<T>::sortInt(SortableVector<int> x, int z) {
int i, j;
int temp = 0;
for (i = 0; i < z - 1; i++) {
for (j = 0; j < z - 1; j++) {
if (x[j] > x[j + 1]) {
temp = x[j];
x[j] = x[j + 1];
x[j + 1] = temp;
}
}
}
}
template<class T>
void SortableVector<T>::print() const {
for (int k = 0; k < vectorSize; k++) {
cout << aptr[k] << " ";
}
cout << endl;
}
Your operator[] returns a reference to the element, which will allow people to directly change the element. The problem happens when you try to use the operator on a const object (when you used const references to pass things to functions). This will allow someone to change the object through that reference returned by operator[], which breaks const-correctness and therefore is not allowed.
In case you're sill confused, let's say you have some class like this:
class Foo
{
private:
int numbers[100];
public:
int& operator[](const int & pos)
{
return numbers[pos];
}
};
This works fine for creating an object and using the bracket operator to access the elements. However, when you try to create a const object:
const Foo f;
You can do something like this:
f[3] = 5;
operator[] returns a reference, which can be used to directly change the data stored in f. f is declared as const though, so this must not happen and the compiler gives an error.
The solution would be to have two versions of operator[], overloaded by their const-ness:
class Foo
{
private:
int numbers[100];
public:
int& operator[](const int &pos)
{
return numbers[pos];
}
const int& operator[](const int &pos) const
{
return numbers[pos];
}
};

RUN FAILED (exit value -1.073.740.940 )

I'm quite new to c++ and netbeans and have quite a problem here and I can't put my finger on what the error might be.
Building is always succesful but I get a RUN FAILED (exit value -1.073.740.940, total time: 2s) error, when running my program. My code:
Arraylist.hpp:
#include <iostream>
namespace hfu {
class Arraylist {
private:
double* members;
int size;
public:
Arraylist(int);
~Arraylist();
Arraylist(const Arraylist&);
double get(int) const;
void set(int, double);
Arraylist& operator=(const Arraylist&);
//float operator[](int);
friend std::ostream& operator<<(std::ostream&, const Arraylist&);
};
}
Arraylist.cpp:
#include "Arraylist.hpp"
#include <exception>
namespace hfu {
Arraylist::Arraylist(int i) : size(i), members(new double[size]) {
for (int i = 0; i < size; i++) {
set(i, 0);
}
}
Arraylist::~Arraylist() {
delete members;
}
Arraylist::Arraylist(const Arraylist& other) : size(other.size), members(new double[other.size]) {
for (int i = 0; i < 5; i++) {
set(i, other.get(i));
}
}
double Arraylist::get(int i) const {
if (i < 0 || i >= size) {
throw (std::exception());
} else {
return members[i];
}
}
void Arraylist::set(int i, double value) {
if (i < 0 || i >= size) {
throw (std::exception());
} else {
members[i] = value;
}
}
Arraylist& Arraylist::operator=(const Arraylist& other) {
size = other.size;
for (int i = 0; i < size; i++) {
set(i, other.get(i));
}
return *this;
}
// float Arraylist::operator [](int index) {
// return members[index];
// }
std::ostream& operator<<(std::ostream& os, const Arraylist& list) {
for (int i = 0; i < list.size; i++) {
os << "[" << list.get(i) << "]";
}
return os;
}
}
main.cpp:
#include "Arraylist.hpp"
int main() {
try {
auto a1 = hfu::Arraylist(10);
std::cout << a1 << std::endl;
auto a2 = hfu::Arraylist(10);
std::cout << a2 << std::endl;
auto a3 = hfu::Arraylist(10);
std::cout << a3 << std::endl;
}
catch (std::exception& e) {
std::cout << e.what() << std::endl;
}
}
I can create 2 objects of Arraylist.... but not more, it will print the first two and then fail.... but when I create shorter lists, say 3 with only size one... it will work... so I think it might be something with the memory... but I'm at a loss. Ideas?
Thanks a lot!
btw: I'm using netbeans 8.2 and mingw g++ 6.1.0
The initialization order of the member variables is defined by the order of their definitions in the class, not by their order in the initializer list. As a matter of fact, your compiler should be giving you "hfu::Arraylist::size will be initialized after" warnings.
So in your case, members gets initialized before size, thus new double[size] is called when size is still garbage. In my case it simply causes std::bad_array_new_length to be thrown. In your case, things go worse and your application crashes.
So the solution is to change
class Arraylist {
private:
double* members;
int size;
to
class Arraylist {
private:
int size;
double* members;

What happens if I "slice" to an abstract class

First off, I know the assignment operator cannot be defined in a class that has some subclasses. I understand it is because we don't want to make Subclass1 = Subclass2 possible.
But let's assume Class is an abstract class and Subclass is its... ya know. Then, is it feasible to do something like this?
Class* p = new Subclass;
Subclass s1;
*p = s1;
Actually, I tried implementing that in my code, but it didn't work :)
Could you please help?
My full code:
#include <cstdlib>
#include <iostream>
#include <typeinfo>
using namespace std;
class BadIndex{
int index;
public:
BadIndex(int i):index(i){}
int getIndex(){ return index; }
};
template <typename t>
class Wielomian{
public:
~Wielomian(){}
virtual int getDeg() = 0;
virtual t& operator [](int) = 0;
virtual bool operator ==(Wielomian<t>&) = 0;
virtual Wielomian<t>& operator +(Wielomian<t>&) = 0;
virtual Wielomian<t>& operator +=(Wielomian<t>&) = 0;
};
template <typename t>
class TabWiel: public Wielomian<t>{
int deg;
t* plnml;
public:
TabWiel(t tab[] = {}, int size = 0);
~TabWiel();
TabWiel(const TabWiel<t>&);
TabWiel<t>& operator =(const TabWiel<t>&);
template <typename st>
friend ostream& operator <<(ostream& s, TabWiel<st>& tw);
int getDeg(){ return deg; }
t& operator [](int);
bool operator ==(Wielomian<t>&);
TabWiel<t>& operator +(Wielomian<t>&);
TabWiel<t>& operator +=(Wielomian<t>&);
};
template <typename t>
TabWiel<t>& TabWiel<t>::operator =(const TabWiel<t>& tw){
if (this != &tw){
delete[] plnml;
deg = tw.deg;
plnml = new t[deg + 1];
for (int i = 0; i < deg + 1; i++)
plnml[i] = tw.plnml[i];
}
return *this;
}
template <typename t>
TabWiel<t>::TabWiel(t tab[], int size){
deg = size - 1;
plnml = new t[deg + 1];
for (int i = 0; i < deg + 1; i++)
plnml[i] = tab[i];
if (deg == -1){
deg = 0;
plnml[0] = 0;
}
}
template <typename t>
TabWiel<t>::~TabWiel(){
delete[] plnml;
}
template <typename t>
TabWiel<t>::TabWiel(const TabWiel<t>& tw){
deg = tw.deg;
plnml = new t[deg + 1];
for (int i = 0; i < deg + 1; i++)
plnml[i] = tw.plnml[i];
}
template <typename t>
t& TabWiel<t>::operator [](int s){
if (s >= 0 && s < deg + 1)
return plnml[s];
else
throw BadIndex(s);
}
template <typename t>
bool TabWiel<t>::operator ==(Wielomian<t>& tw){
try{
TabWiel<t>& rhs = dynamic_cast<TabWiel<t>&>(tw);
if (deg == rhs.deg){
for (int i = 0; i < deg + 1; i++){
if (plnml[i] != rhs.plnml[i])
return false;
}
return true;
}
return false;
}
catch (const bad_cast& e){
cerr << "An exception" << e.what() << " thrown." << endl;
}
}
template <typename t>
ostream& operator <<(ostream& s, TabWiel<t>& tw){
for (int i = 0; i < tw.deg + 1; i++){
if (i != tw.deg)
s << tw.plnml[i] << "x^" << i << "+";
else
s << tw.plnml[i] << "x^" << i << endl;
}
return s;
}
template <typename t>
TabWiel<t>& TabWiel<t>::operator +(Wielomian<t>& tw){
try{
TabWiel<t>& rhs = dynamic_cast<TabWiel<t>&>(tw);
if (rhs.deg <= deg){
for (int i = 0; i < rhs.deg + 1; i++)
plnml[i] = plnml[i] + rhs.plnml[i];
return *this;
}
else{
t* tmp = new t[deg + 1];
for (int i = 0; i < deg + 1; i++)
tmp[i] = plnml[i];
int tmp_deg = deg;
delete[] plnml;
deg = rhs.deg;
plnml = new t[deg + 1];
for (int i = 0; i < deg + 1; i++){
if(i < tmp_deg + 1)
plnml[i] = tmp[i] + rhs.plnml[i];
else
plnml[i] = rhs.plnml[i];
}
return *this;
}
}
catch (const bad_cast& e){
cerr << "An exception" << e.what() << " thrown." << endl;
}
}
template <typename t>
TabWiel<t>& TabWiel<t>::operator +=(Wielomian<t>& tw){
try{
TabWiel<t>& rhs = dynamic_cast<TabWiel<t>&>(tw);
TabWiel<t>* nowy = new TabWiel<t>;
TabWiel<t> copy;
copy = *this;
*nowy = copy + rhs;
return *nowy;
}
catch (const bad_cast& e){
cerr << "An exception" << e.what() << " thrown." << endl;
}
}
I wish the assignment of *p to non-empty subclass object worked. But it doesn't - all the code does, is that it enters "Wielomian" definition and then proceeds to the next line of the main function (which in my case is the last line).
Your question is very interesting.
First of all, your code doesn't work because of slicing: you have two objects of Subclass, but
the compiler thinks that one of it is only a Class. So the code generated copies only the common
part of the data.
To demonstrate this, let's ellaborate on gha.st 's initial code extract:
struct Class { int a; virtual void hugo() = 0; };
struct Subclass : Class { int b; void hugo() override { cout<<"sub"<<a<<b<<endl; } };
int main() {
Class* p = new Subclass;
static_cast<Subclass*>(p)->a = 2;
static_cast<Subclass*>(p)->b = 3;
Subclass s1;
s1.a = 4; s1.b=5;
*p = s1; // slicing !!
p->hugo();
return 0;
}
What happens here ? Well, b member isn't copied, although *p is in reality a Subclass !
But *p is still a Subclass, so we could use polymorphism to get this work. The trick is to use an virtual clone() member to clone
an object (the object shall know its own type) into a target, if the target has the same type.
Then you could define operator=() for Class to use this clone(). This makes it handy to use, but the drawback is that you'll no longer
be able to rely on default operator= for any descendent of Class if you want to avoid an endless recursion.
Here the proof of concept:
struct Class {
int a;
virtual void hugo() = 0;
virtual bool clone(Class*t) = 0;
Class& operator=(Class& o) {
if (!o.clone(this)) { // try to clone on subclass on a target of same subclass
// here,the source and target might differ. Only common members can be copied
a = o.a;
}
return *this;
}
};
struct Subclass : Class {
int a,b;
void hugo() override { cout<<"sub"<<a<<b<<endl; }
bool clone(Class*t) {
cout<<"Clone ";
if (dynamic_cast<Subclass*>(t)) { // if source and target of same subclass
//*dynamic_cast<Subclass*>(t) = *this; // this doesn't work cause default operator will try to copy the Class base, causing recursion
dynamic_cast<Subclass*>(t)->a = a; // copy members
dynamic_cast<Subclass*>(t)->b = b;
return true;
}
else return false; // or tell that class of source and target are different.
}
};
Then you can use the main() function above, and see that the object is properly copied.
This trick is a kind of simplified double dispatch. You could even elaborate further by foreseing various kind of conversions depending on source and target subtype.