Copy doesn't work in my string::copy implementation - c++

Following up on https://codereview.stackexchange.com/q/126242/23788.
I wrote my string class and according to the feedback I have changed some stuff. Is there anything more that should be fixed?
+operator doesn't work and I do not know what I've done wrong. I have a segfault when I do "Str+Str".
Process finished with exit code 139
And this is my Str.h
class Str {
friend std::istream &operator>>(std::istream &, Str &);
friend void swap(Str &s, Str &t) {
std::swap(s.data, t.data);
std::swap(s.length, t.length);
std::swap(s.alloc, t.alloc);
}
public:
typedef char *iterator;
typedef size_t size_type;
Str() : data(nullptr), length(0), capacity(0) { }
Str(size_type length, char char_to_fill) : Str() { create(length, char_to_fill); }
Str(const char *s) : Str() { create(s); }
template<class In>
Str(In b, In e) : Str() { create(b, e); }
~Str() {
if (data) alloc.deallocate(data, capacity);
data = nullptr;
}
Str(const Str &s) {
*this = s;
}
// move constructor?
Str(Str &&other)
: Str() {// initialize via default constructor, C++11 only
swap(*this, other);
}
Str &operator+=(const Str &s) {
size_type new_length = length + s.length - 1; //remove 1 because of 2 nulls
if (new_length > capacity) {
reallocate(new_length);
strcpy(data + length - 1, s.data); //overwrite null from s
length = new_length;
}
else {//if there was already enough space
strcpy(data + length - 1, s.data);
}
return *this;
}
Str &operator=(Str rhs) {
swap(*this, rhs);
return *this;
}
char &operator[](size_type i) { return data[i]; };
const char &operator[](size_type i) const { return data[i]; };
size_type size() { return length; }
const size_type size() const { return length; }
const char *c_str() const {
return data;
}
void copy(char *dest, size_type n) {
if (n > length)
throw std::out_of_range("Out of range");
std::copy(data, data + n, dest);
}
char *begin() { return data; };
char *end() { return data + length; };
void push_back(char c) {
if (length == capacity) {
reallocate(capacity == 0 ? DEFAULT_CAPACITY : 2 * capacity);
}
data[length++] = c;
}
private:
char *data;
std::allocator<char> alloc;
size_type length;
size_type capacity;
static const size_type DEFAULT_CAPACITY = 20;
void create(size_type n, char character_to_fill) {
capacity = length = n + 1;
data = alloc.allocate(capacity);
std::uninitialized_fill(data, data + length - 1, character_to_fill);
//alloc.construct(data + length - 1, '\0'); //is it needed to be constructed?
data[length - 1] = '\0';
}
void create(const char *s) {
capacity = length = strlen(s) + 1;
data = alloc.allocate(capacity);
strcpy(data, s);
//alloc.construct(data + length - 1, '\0');
data[length - 1] = '\0';
}
template<class In>
void create(In b, In e) {
capacity = e - b + 1;
data = alloc.allocate(capacity);
while (b != e) {
data[length++] = *(b++);
}
//alloc.construct(data + length -1, '\0');
data[length++] = '\0';
}
void reallocate(size_t new_capacity) {
char *new_data = alloc.allocate(new_capacity);
std::copy(data, data + length, new_data);
alloc.deallocate(data, length);
data = new_data;
capacity = new_capacity;
}
};
std::istream &operator>>(std::istream &is, Str &s) {
std::vector<char> buf;
char actual_character;
while (is.get(actual_character) && isspace(actual_character)) { ;
}
if (is) { //is it correct to check "is" ?
do buf.push_back(actual_character);
while (is.get(actual_character) && !isspace(actual_character));
if (is)
is.unget();
}
s.create(buf.begin(), buf.end());
return is;
}
std::ostream &operator<<(std::ostream &os, const Str &s) {
os << s.c_str();
return os;
}
Str operator+(Str lhs, const Str &rhs) {
lhs += rhs;
return lhs;
}
And example main.cpp
#include <iostream>
#include <vector>
#include "Str.h"
using std::cout;
using std::endl;
int main() {
Str s("Siema");
cout<<s.c_str()<<endl;
s = "Hello";
cout<<s<<endl;
s.push_back('a');
cout<<s<<endl;
Str t = "World";
//cout<<s+t<<endl; //THIS DOESNT WORK
s+=t;
cout<<s<<endl;
cout<<s[3]<<s[5]<<s[11]<<endl;
cout<<s.size()<<endl;
cout<<Str(s.begin()+3, s.end()-2)<<endl;
for(Str::iterator i = s.begin(); i<s.end() ; i+=2){
cout<<i<<endl;
}
char copied[3];
t.copy(copied, 4);
cout<<copied<<endl;
return 0;
}

In your code
char copied[3];
t.copy(copied, 4);
cout<<copied<<endl;
"copied" has only length of 3 while you are trying to copy 4 characters into it. Which will cause problem
Check updated codes below. Read comments with "<--"
str.h
#include <iostream>
#include <memory>
#include <vector>
class Str {
friend std::istream &operator >> (std::istream &, Str &);
void swap(Str &s, Str &t) {
std::swap(s.data, t.data);
std::swap(s.length, t.length);
std::swap(s.alloc, t.alloc);
}
public:
typedef char *iterator;
typedef size_t size_type;
Str() : data(nullptr), length(0), capacity(0) { }
Str(size_type length, char char_to_fill) : Str() { create(length, char_to_fill); }
Str(const char *s) : Str() { create(s); }
template<class In>
Str(In b, In e) : Str() { create(b, e); }
~Str() {
if (data) alloc.deallocate(data, capacity);
data = nullptr;
}
Str(const Str &s) {
*this = s;
}
// move constructor?
Str(Str &&other)
: Str() {// initialize via default constructor, C++11 only
swap(*this, other);
}
Str &operator+=(const Str &s) {
size_type new_length = length + s.length - 1; //remove 1 because of 2 nulls
if (new_length > capacity) {
reallocate(new_length);
strcpy(data + length - 1, s.data); //overwrite null from s
//length = new_length; //<-- You need to update the length anyay. Move it to before return
}
else {//if there was already enough space
strcpy(data + length - 1, s.data);
}
length = new_length; //<-- update the length
return *this;
}
Str &operator=(Str rhs) {
swap(*this, rhs);
return *this;
}
char &operator[](size_type i) { return data[i]; };
const char &operator[](size_type i) const { return data[i]; };
size_type size() { return length; }
const size_type size() const { return length; }
const char *c_str() const {
return data;
}
void copy(char *dest, size_type n) {
if (n > length)
throw std::out_of_range("Out of range");
std::copy(data, data + n, dest); // <--forgot about '\0'?
dest[n] = '\0'; // <-- add '\0'
}
char *begin() { return data; };
char *end() { return data + length; };
void push_back(char c) {
if (length == capacity) {
reallocate(capacity == 0 ? DEFAULT_CAPACITY : 2 * capacity);
}
data[length++ - 1] = c; //<-- length - 1 is the last position, because length here includes '\0'
data[length - 1] = 0; //<-- don't forget to add '\0'. It's better if you fill the unused spaces to '\0' after allocate them.
}
private:
char *data;
std::allocator<char> alloc;
size_type length;
size_type capacity;
static const size_type DEFAULT_CAPACITY = 20;
void create(size_type n, char character_to_fill) {
capacity = length = n + 1;
data = alloc.allocate(capacity);
std::uninitialized_fill(data, data + length - 1, character_to_fill);
//alloc.construct(data + length - 1, '\0'); //is it needed to be constructed?
data[length - 1] = '\0';
}
void create(const char *s) {
capacity = length = strlen(s) + 1;
data = alloc.allocate(capacity);
strcpy(data, s);
//alloc.construct(data + length - 1, '\0');
data[length - 1] = '\0';
}
template<class In>
void create(In b, In e) {
capacity = e - b + 1;
data = alloc.allocate(capacity);
while (b != e) {
data[length++] = *(b++);
}
//alloc.construct(data + length -1, '\0');
data[length++] = '\0';
}
void reallocate(size_t new_capacity) {
char *new_data = alloc.allocate(new_capacity);
std::copy(data, data + length, new_data);
alloc.deallocate(data, length);
data = new_data;
capacity = new_capacity;
}
};
std::istream &operator >> (std::istream &is, Str &s) {
std::vector<char> buf;
char actual_character;
while (is.get(actual_character) && isspace(actual_character)) {
;
}
if (is) { //is it correct to check "is" ?
do buf.push_back(actual_character);
while (is.get(actual_character) && !isspace(actual_character));
if (is)
is.unget();
}
s.create(buf.begin(), buf.end());
return is;
}
std::ostream &operator<<(std::ostream &os, const Str &s) {
os << s.c_str();
return os;
}
Str operator+(Str lhs, const Str &rhs) {
lhs += rhs;
return lhs;
}
and main:
int main() {
Str s("Siema");
cout << s.c_str() << endl;
s = "Hello";
cout << s << endl;
s.push_back('a');
cout << s << endl;
Str t = "World";
//cout<<s+t<<endl; //THIS DOESNT WORK
s += t;
cout << s << endl;
cout << s[3] << s[5] << s[11] << endl;
cout << s.size() << endl;
cout << Str(s.begin() + 3, s.end() - 2) << endl;
for (Str::iterator i = s.begin(); i<s.end(); i += 2) {
cout << i << endl;
}
char copied[5]; //<-- was 3, not enough space
t.copy(copied, 4);
cout << copied << endl;
return 0;
}

Related

Serialize arbitrary trivially cpyable non array "stuff" into buffer (reinterpret_cast) goes wrong

The title is self-explanatory: I want to serialize an arbitrary large amount of trivially copyable non array "stuff" into a buffer (for academic reasons).
The basic idea is to reinterpret_cast the address of what I want to serialize as an unsigned char*, and then use std::copy into that buffer, and do the reverse operation to load.
Here's a minimal non working example.
#include <iostream>
struct A
{
int i, j;
};
int main()
{
int i = -1;
A a {23, 42};
unsigned char* buffer = new unsigned char[20];
const unsigned char* to_serialize = reinterpret_cast<const unsigned char*>(&i);
std::copy(to_serialize, to_serialize + sizeof(int), buffer);
int offset = sizeof(int);
to_serialize = reinterpret_cast<const unsigned char*>(&a);
std::copy(to_serialize, to_serialize + sizeof(A), buffer + offset);
unsigned char serialized_i[sizeof(int)];
std::copy(buffer, buffer + sizeof(int), serialized_i);
int ii (*reinterpret_cast<int*>(serialized_i));
std::cout << ii << std::endl; //outputs -1 -> ok
unsigned char serialized_a[sizeof(A)];
std::copy(buffer + offset, buffer + offset + sizeof(A), serialized_a);
A aa(*reinterpret_cast<A*>(serialized_a));
std::cout << aa.i << " " << aa.j << std::endl; //suspect there is a bug
}
If I only write an A, it works fine. I can also write an arbitrary amounts of ints, it works as well. But as soon as I mix the two (as done above), it fails.
On the above example, it "seems" to work. On the full code (below), it doesn't.
File bytebuffer.h
#ifndef BYTEBUFFER_H
#define BYTEBUFFER_H
#include <vector>
#include <stdexcept>
#include <iostream>
#include <memory>
template<class T>
concept TriviallyCopyable = ! std::is_array_v<T> && std::is_trivially_copyable_v<T>;
using byte = unsigned char;
class ByteBuffer
{
byte * _buffer;
std::vector<size_t> _offsets;
size_t _size;
size_t _capacity;
public:
ByteBuffer(size_t capacity = 100);
//Rule of 5 with copy and swap idiom
~ByteBuffer();
ByteBuffer(const ByteBuffer& buffer);
ByteBuffer& operator=(const ByteBuffer& buffer);
ByteBuffer(ByteBuffer&& buffer) noexcept;
ByteBuffer& operator=(ByteBuffer&& buffer) noexcept;
void swap(ByteBuffer& buffer) noexcept;
//basic accessors
const byte* buffer() const;
const std::vector<size_t>& offsets() const;
size_t size() const; //size in bytes
size_t capacity() const; //capacity in bytes
bool reserve(size_t max_size);
void clear();
//storage
template<TriviallyCopyable T>
size_t store(const T& t);
template<TriviallyCopyable T>
T load(size_t offset) const;
//I need to write overloads for arrays
void dump(std::ostream& out, bool clear = true);
};
void swap(ByteBuffer& buffer1, ByteBuffer& buffer2) noexcept;
///////////////////////////////////////////////////////// IMPLEMENTATIONS
template<TriviallyCopyable T>
size_t ByteBuffer::store(const T& t)
{
if(_buffer == nullptr)
throw std::runtime_error("Storage buffer is nullptr");
if(_offsets.back() + sizeof(T) > _capacity)
reserve(2 * _capacity);
size_t offset = _offsets.back() + sizeof(T); //where we need to store
const byte* serialized = reinterpret_cast<const byte*>(std::addressof(t)); //better than &t
std::copy(serialized, serialized + sizeof(T), _buffer + offset);
_offsets.push_back(offset);
_size += offset;
return offset;
}
template<TriviallyCopyable T>
T ByteBuffer::load(size_t offset) const
{
if(_buffer == nullptr)
throw std::runtime_error("Storage buffer is nullptr");
byte serialized[sizeof(T)];
std::copy(_buffer + offset, _buffer + offset + sizeof(T), serialized);
return T(*reinterpret_cast<T*>(serialized)); //force copy
}
#endif
File bytebuffer.cpp
#include "bytebuffer.h"
#include <algorithm>
ByteBuffer::ByteBuffer(size_t capacity) : _buffer(capacity > 0 ? new byte[capacity] : nullptr), _offsets({0}), _size(0), _capacity(capacity)
{//remark: there is always at least '0' in the offset list, because when the buffer is empty, the first free spot has offset 0
if(capacity > 0)
std::fill(_buffer, _buffer + capacity, 0);
}
const unsigned char* ByteBuffer::buffer() const //alias not working here, since it's out of scope
{
return _buffer;
}
const std::vector<size_t>& ByteBuffer::offsets() const
{
return _offsets;
}
size_t ByteBuffer::size() const
{
return _size;
}
size_t ByteBuffer::capacity() const
{
return _capacity;
}
bool ByteBuffer::reserve(size_t max_size)
{
if(max_size <= _capacity)
return false;
try
{
byte* newbuffer = new byte[max_size]; //might throw
std::copy(_buffer, _buffer + _size, newbuffer);
_capacity = max_size;
delete[] _buffer;
_buffer = newbuffer;
return true;
}
catch(...)
{
return false;
}
}
void ByteBuffer::clear()
{
std::fill(_buffer, _buffer + _capacity, 0);
_offsets.clear();
_offsets.push_back(0);
_size = 0;
}
void ByteBuffer::dump(std::ostream& out, bool clear)
{
std::for_each(_buffer, _buffer + _size, [&out](byte c){ out << c; });
if(clear)
this->clear();
}
std::ostream& operator<<(std::ostream& out, ByteBuffer& buffer)
{
buffer.dump(out, false);
return out;
}
/////////////////////////// RULE OF 5
void ByteBuffer::swap(ByteBuffer& other) noexcept
{
std::swap(_buffer, other._buffer);
std::swap(_offsets, other._offsets);
std::swap(_size, other._size);
std::swap(_capacity, other._capacity);
}
void swap(ByteBuffer& buffer1, ByteBuffer& buffer2) noexcept
{
buffer1.swap(buffer2);
}
ByteBuffer::~ByteBuffer()
{
if(_buffer)
{
delete[] _buffer;
_buffer = nullptr;
}
}
ByteBuffer::ByteBuffer(const ByteBuffer& other) : _buffer(new byte[other._capacity]), _offsets(other._offsets), _size(other._size), _capacity(other._capacity)
{
std::copy(other._buffer, other._buffer + _capacity, _buffer);
}
ByteBuffer& ByteBuffer::operator=(const ByteBuffer& other)
{
ByteBuffer tmp(other);
swap(tmp);
return *this;
}
ByteBuffer::ByteBuffer(ByteBuffer&& other) noexcept : ByteBuffer()
{
swap(other);
}
ByteBuffer& ByteBuffer::operator=(ByteBuffer&& other) noexcept
{
swap(other);
if(other._buffer != nullptr)
{
delete[] other._buffer;
other._buffer = nullptr;
}
return *this;
}
File main.cpp
#include <iostream>
#include "bytebuffer.h"
#include <type_traits>
#include <iomanip>
using namespace std;
struct A
{
int i, j;
};
int main()
{
ByteBuffer buffer;
size_t offset1 = buffer.store(2);
size_t offset2 = buffer.store(3.5);
A a {23, 42};
cout << "sizeof A : " << sizeof(a) << endl;
cout << "A has " << a.i << " " << a.j << endl;
cout << boolalpha << is_trivially_copyable<A>::value << endl << endl;
size_t offset3 = buffer.store(a);
size_t offset4 = buffer.store('d');
//size_t offset5 = buffer.store("Hello"); //doesn't work with arrays, I need a specific template overload
//size_t offset6 = buffer.store(std::string("Hello")); //doesn't compile, and that's ok
//no template argument deduction possible down here, that's normal, and ok
cout << buffer.load<int>(offset1) << endl; //2
cout << buffer.load<double>(offset2) << endl; //3.5
A loaded = buffer.load<A>(offset3); //runs, but wrong atrtibutes
cout << loaded.i << " " << loaded.j << endl; //error: wrong value
cout << buffer.load<char>(offset4) << endl; //d
//cout << buffer.load<const char[6]>(offset5) << endl; //doesn't work with arrays, I need a specific template overload
//cout << buffer.load<std::string>(offset6) << endl; //doesn't compile, and that's ok
}
So, the first mwe works fine, as stated in the comments. And, for the complete fix, the error was how I stored my offsets in the _offset attribute.
I rewrote the store member function as follows:
template<TriviallyCopyable T>
size_t ByteBuffer::store(const T& t)
{
if(_buffer == nullptr)
throw std::runtime_error("Storage buffer is nullptr");
if(_offsets.back() + sizeof(T) > _capacity)
reserve(2 * _capacity);
size_t offset = _offsets.back(); //where we need to store
const byte* serialized = reinterpret_cast<const byte*>(std::addressof(t)); //better than &t
std::copy(serialized, serialized + sizeof(T), _buffer + offset);
_offsets.push_back(offset + sizeof(T));
_size += sizeof(T);
return offset;
}

error: conversion from ‘const char [5]’ to non-scalar type ‘String’ requested

I am trying to create a class String which can be assigned by operator=. But the compiler shows an error:
error: conversion from ‘const char [5]’ to non-scalar type ‘String’ requested
Can anyone help me to fix it?
#include <iostream>
using namespace std;
class String
{
private:
char string[];
public:
void operator=(const char str[])
{
for (int i = 0; ; i++) {
if (str[i] == '\0') {
string[i] = str[i];
break;
} else {
string[i] = str[i];
}
}
}
friend ostream &operator<<(ostream &output, const String& str)
{
output << str.string;
return output;
}
};
int main()
{
String str1 = "test";
cout << str1 << endl;
}
String str1 = "test"; does not use operator= at all. It is just syntax sugar for String str1("test");, which uses a conversion constructor that you have not defined yet, hence the compiler error. You need to add such a constructor.
Also, char string[]; is not a valid variable declaration for an array. You need to specify a size for the array, and then make sure the class never exceeds that size.
For example
#include <iostream>
#include <cstring>
using namespace std;
class String {
private:
char string[256];
public:
String(const char *str = NULL) {
if (str) strncpy(string, str, sizeof(string)-1);
string[sizeof(string)-1] = '\0';
}
String& operator=(const String &str) {
if (this != &str) {
memcpy(string, str.string, sizeof(string));
}
return *this;
}
friend ostream& operator<<(ostream &output, const String& str) {
output << str.string;
return output;
}
};
int main() {
String str1 = "test";
cout << str1 << endl;
}
However, in this situation, using a dynamically allocated array makes more sense than using a fixed array. Just be sure to follow the Rule of 3 for proper memory management.
Try this instead:
#include <iostream>
#include <cstring>
using namespace std;
class String {
private:
char *string;
int length;
int capacity;
public:
String(const char *str = NULL)
: string(NULL), length(0), capacity(0)
{
if ((str) && (*str != '\0')) {
length = capacity = strlen(str);
string = new char[length + 1];
memcpy(string, str, length + 1);
}
}
String(const String &str)
: string(NULL), length(0), capacity(0)
{
if (str.string) {
length = capacity = str.length;
string = new char[length + 1];
memcpy(string, str.string, length + 1);
}
}
~String() {
delete[] string;
}
String& operator=(const String &str) {
if (this != &str) {
int len = str.length;
if (capacity >= len) {
memcpy(string, str.string, len + 1);
}
else {
int cap = int(double(len) * 1.5);
char *temp = new char[cap + 1];
memcpy(temp, str.string, len + 1);
delete[] string;
string = temp;
capacity = cap;
}
length = len;
}
return *this;
}
friend ostream& operator<<(ostream &output, const String& str) {
if (str.string) {
output.write(str.string, str.length);
}
return output;
}
};
int main() {
String str1 = "test";
cout << str1 << endl;
}
You need to add a ctor to your class. You are using the assignment operator to try to construct your String object. Add this to your class.
String(const char str[]) {
for (int i = 0; ; i++) {
if (str[i] == '\0') {
string[i] = str[i];
break;
} else {
string[i] = str[i];
}
}
}

Repeating words in string class

So I have to write a string class, and I need help with reading from a file into a vector of string classes I've created. It somewhat works, as it reads from the file but it repeats the the word read in a few times depending on which word it's on.
// .h
/*Class description:
A string class. Various functions for the class.
String is passed into objects of the class. Reads
and writes to files.*/
#ifndef MYString12_H
#define MYString12_H
#include <fstream>
using namespace std;
class MYString12
{
public:
MYString12();
MYString12(const MYString12 & mstr);
MYString12(const char* ptr);
~MYString12();
MYString12& operator = (const MYString12& argStr);
friend MYString12 operator + (const MYString12& str1, const MYString12& str2);
char operator [] (int index);
bool operator > (const MYString12& argStr2);
bool operator < (const MYString12& argStr2);
bool operator == (const MYString12& argStr);
friend istream& operator >> (istream& istr, MYString12& argStr);
friend ostream& operator << (ostream& istr, MYString12& argStr);
int length() const;
int capacity()const;
char at(int index);
const char* c_str()const;
static int getCurrentCount();
static int getCreatedCount();
private:
char* str;
int cap = 20;
int end;
const int compareTo(const MYString12& argStr);
static int currentCount;
static int createdCount;
};
#endif
Here is class cpp file
// MYString12.cpp
#include "stdafx.h"
#include "MYString12.h"
#include <iostream>
#include <iomanip>
#include <math.h>
#include <cstdlib>
using namespace std;
int MYString12::createdCount = 0;
int MYString12::currentCount = 0;
// default constructor
MYString12::MYString12()
{
cap = 20;
end = 0;
str = new char[cap];
str[end] = '\0';
createdCount++;
currentCount++;
}
// copy constructor
MYString12::MYString12(const MYString12& mstr)
{
this->end = mstr.end;
this->cap = mstr.cap;
this->str = new char[mstr.cap];
while (end >= cap) {
cap += 20;
}
for (int i = 0; i < end; i++) {
str[i] = mstr.str[i];
}
//mstr.str[end] = '\0';
createdCount++;
currentCount++;
}
// constructor with string passed in
MYString12::MYString12(const char* ptr)
{
int i = 0;
while (ptr[i] != '\0') {
end++;
i++;
}
while (end >= cap) {
cap += 20;
}
str = new char[cap];
for (int j = 0; j < end; j++) {
str[j] = ptr[j];
}
createdCount++;
currentCount++;
}
// destructor
MYString12::~MYString12()
{
delete[] str;
currentCount--;
}
// overloaded assignment operator
GAString12& GAString12::operator = (const GAString12& mstr)
{
if (this == &mstr) {
return *this;
}
this->end = mstr.end;
this->cap = mstr.cap;
while (end >= cap) {
cap += 20;
}
for (int i = 0; i < end; i++) {
str[i] = mstr.str[i];
}
//mstr.str[end] = '\0';
return *this;
}
// overloaded concatanation operator
MYString12 operator + (const MYString12& str1, const MYString12& str2)
{
int temp = str1.end + str2.end + 1;
char tempArray[200];
int i = 0;
int j = 0;
while (i < temp)
{
if (i < str1.end)
{
tempArray[i] = str1.str[i];
i++;
} else {
tempArray[i] = str2.str[j];
i++;
j++;
}
}
tempArray[i] = '\0';
MYString12 concatenatedObj(tempArray);
return concatenatedObj;
}
// overloaded index operator
char MYString12::operator [] (int index)
{
return str[index];
}
// overloaded greater than operator
bool MYString12::operator > (const MYString12& argStr)
{
if ((*this).compareTo(argStr) > 0)
{
return true;
}
else {
return false;
}
}
// overloaded less than operator
bool MYString12::operator < (const MYString12& argStr)
{
if ((*this).compareTo(argStr) < 0)
{
return true;
}
else {
return false;
}
}
// overloaded equals equals operator
bool MYString12::operator == (const MYString12& argStr)
{
if ((*this).compareTo(argStr) == 0)
{
return true;
}
else {
return false;
}
}
// compares ascii values of objStr and argStr
const int MYString12::compareTo(const MYString12& argStr)
{
int asciiSubtraction = 0;
int limit = 0;
if (end <= argStr.end)
{
limit = end;
}
else {
limit = argStr.end;
}
int i = 0;
while (i <= limit && (str[i] == argStr.str[i])) {
i++;
}
asciiSubtraction = str[i] - argStr.str[i];
return asciiSubtraction;
}
// overloaded extraction operator
istream& operator >> (istream& istr, MYString12& argStr)
{
char temp[100];
istr >> temp;
argStr = GAString12(temp);
return istr;
}
// overloaded insertion operator
ostream& operator << (ostream& ostr, MYString12& argStr)
{
int i = 0;
while (argStr.str[i] != '\0')
{
ostr << argStr.str;
i++;
}
return ostr;
}
// returns size of passed in string
int MYString12::length() const
{
return end;
}
// returns size of memory allocated
int MYString12::capacity() const
{
return cap;
}
// returns a char of string at passed index
char MYString12::at(int index)
{
if (index < 0 || index > end) {
return '\0';
}
else {
return str[index];
}
}
// returns passed in string as c string
const char* MYString12::c_str() const
{
createdCount++;
currentCount++;
return str;
}
// returns the amount of alive instances of class
int MYString12::getCurrentCount()
{
return currentCount;
}
// returns the amount of overall created instances of class
int MYString12::getCreatedCount()
{
return createdCount;
}
And here is main
// main
int main()
{
vector<MYString12> word(100);
ifstream fin;
fin.open("infile3.txt");
if (fin.fail()) {
cout << "Error." << endl;
exit(1);
}
int wordCount = 0;
while (fin >> word[wordCount]) {
cout << word[wordCount];
system("pause");
wordCount++;
}
word.resize(wordCount);
fin.close();endl;
return 0;
}
It doesn't print out to the console any of the words. Nothing is printed. Why doesn't it print?

Memory deallocation of temporary object c++

I build a simple string class.
I try to make the concatenation functions which one of them is + and the other +=.
When trying to implement += I generate a Str object under that equals the 1st string and which size is s.size(). But then when I tried to append to it a new string t I need to free the old array s string and allocate new size for it. After the destructor of the temp Str object is called it stucks there when freeing the old space and I can't understand why. How can I deallocate the Str under the + member function?
class Str
{
public:
typedef size_t size_type;
typedef char* iterator;
typedef const char* const_iterator;
iterator begin(){ return p; }
iterator end() { return p + std::strlen(p); }
const_iterator begin() const { return p; }
const_iterator end() const { return p + std::strlen(p); }
size_type size() const { return data_length; }
Str() {};
Str(const Str& s):
p(new char[s.size() +1]),
data_length(s.size())
{
std::copy(s.begin(), s.end(), p);
p[data_length] = '\0';
}
Str(const char* cp) :
p(new char[std::strlen(cp) + 1 ]),
data_length(std::strlen(cp))
{
std::copy(cp, cp+ std::strlen(cp) + 1,p);//copies also the '\0' char to the last place in p
}
Str& operator=(Str& rhs)//assignment operator
{
if (&rhs != this)
{
uncreate();
create(rhs.size());
std::copy(rhs.begin(), rhs.end() + 1, p);
//p[rhs.size()] = '\0';
}
return *this;
}
Str& operator=(const char* cp)//assignment operator
{
if (cp!= p)
{
uncreate();
create(std::strlen(cp));
std::copy(cp, cp+std::strlen(cp), p);
p[data_length] = '\0';
}
return *this;
}
Str& operator+=(const Str&);
~Str()
{
delete[] p;//stucked here while returning from + member function
data_length = 0;
}
const char* c_str() const;
void copy(char* ,size_type);
private:
char* p;
size_type data_length = 0;
const_iterator ci() const { return p; }
void uncreate();
void create(size_type);
};
Str operator+(const Str& s, const Str& t)
{
Str r = s;
r += t;
return r;
}
inline Str& Str::operator+=(const Str &s)
{
//trying to allocate new space for this object
std::copy(s.begin(),s.end(),p+this->size());
p[data_length] = '\0';
return *this;
}
void Str::create(Str::size_type n)
{
p = new char[n + 1];
data_length = n;
}
void Str::uncreate()
{
delete[] p;//to check that p is allocated right
data_length = 0;
}
The main for example:
int main()
{
Str s1 = "hello";
Str s2 = "worly";
Str s3 = s1 + s2;
return 0;
}
I suppose you want something like this:
inline Str& Str::operator+=(const Str &s)
{
const int new_data_length = data_length + s.data_length;
char * temp = new char[new_data_length + 1];
memcpy(temp, p, data_length);
memcpy(temp + data_length, s.p, s.data_length);
delete [] p;
p = temp;
data_length = new_data_length;
p[data_length] = 0;
return *this;
}

segmentation fault scrabble game

im working on a little scrabblegame which i read a txtfile and create a hashtable for all words inside. Word is a specific class which contains a vector of .
i want to create a hashmap by my own and define the length of my "Dictionary" is 50000. im using a nullpointer to reserve all index of my array. If i want to print to my hashtable, compiler tells me a segmentation fault. does any one seems the error?
the headerfile:
class Dictionary {
public:
Dictionary();
Dictionary(string filepath);
friend std::ostream& operator<<(std::ostream& os, const Dictionary& obj);
bool find(const Word& word);
vector<Word> allPossibleWords(const vector<Character>& tiles);
// struct compare {
//
// bool operator()(const Word& a, const Word& b) {
// return a.operator<(b);
// }
// } myCompare;
vector<Word> m_allWords;
vector<Word>::iterator itVecWords;
static const int table_size = 500000;
// std::array <Word*, table_size> arrWords = {nullptr};
Word* arrWords[table_size] = {nullptr};
int hash(Word new_word);
void addItem(Word word);
void printHashTable();
the cpp:
Dictionary::Dictionary(string filepath) {
ifstream datei(filepath.c_str());
while (datei.good() && !datei.eof()) {
string temp;
string temp1;
string::size_type pos;
getline(datei, temp);
pos = temp.find(" ");
temp1 = temp.substr(0, pos);
Word new_word(temp1);
addItem(new_word);
}
datei.close();
}
std::ostream& operator<<(std::ostream& os, const Dictionary& obj) {
for (int i = 0; i < obj.m_allWords.size(); i++) {
os << obj.m_allWords[i] << endl;
}
return os;
}
bool Dictionary::find(const Word& word) const {
if (std::binary_search(m_allWords.begin(), m_allWords.end(), word)) {
return true;
}
return false;
}
vector<Word> Dictionary::allPossibleWords(const vector<Character>& tiles) const {
vector<Word> ergebnis;
string tmp;
int cnt = 0;
for (int i = 0; i < tiles.size(); i++) {
tmp += tiles[i].GetC();
}
sort(tmp.begin(), tmp.end());
for (int i = 1; i <= tiles.size(); i++) {
do {
string piece = tmp.substr(0, i);
do {
Word search = Word(piece);
//Überschreibt immer der in Ergebnis existierte Wert
if (find(search) && std::find(ergebnis.begin(), ergebnis.end(), search) == ergebnis.end()) {
ergebnis.push_back(search);
}
} while (next_permutation(piece.begin(), piece.end()));
} while (next_permutation(tmp.begin(), tmp.end()));
}
return ergebnis;
}
int Dictionary::hash(Word new_word) {
int index = 0;
for (auto u : new_word.new_Character) {
index += (int) u.GetC();
}
index = index * (int) new_word.new_Character.at(0).GetC();
index = index * (int) new_word.new_Character.at(new_word.new_Character.size() - 1).GetC();
return index % table_size;
}
void Dictionary::addItem(Word word) {
int index = hash(word);
if (arrWords[index] == nullptr) {
arrWords[index] = new Word(word);
} else {
Word* ptr = arrWords[index];
Word* neu = new Word(word);
while (ptr->getNextWord() != nullptr) {
ptr = ptr->getNextWord();
}
ptr->setNextWord(neu);
}
}
void Dictionary::printHashTable() {
Word* tmp;
for (int i = 0; i < table_size; i++) {
tmp = arrWords[i];
if (tmp != nullptr) {
tmp->printWord();
cout << "Index : " << i;
}
tmp = tmp->getNextWord();
}
}
class Word {
public:
Word();
Word(string m_wort);
int length() const;
int points() const;
friend std::ostream& operator<<(std::ostream& os, const Word& obj);
bool operator==(const Word& right) const; /
bool operator!=(const Word& right) const;
bool contains(const Character& c) const;
Word substr(int start, int end) const;
bool operator<(const Word& right) const;
vector <Character> new_Character;
Word* Next = nullptr;
void setNextWord(Word*);
Word* getNextWord();
void printWord();
string getWordAsString();
CPP File:
void Word::setNextWord(Word* w) {
Next = w;
}
Word* Word::getNextWord() {
return Next;
}
void Word::printWord() {
string s = "";
for (int i = 0; i < new_Character.size(); i++) {
s += new_Character.at(i).GetC();
}
cout << s << endl;
}
string Word::getWordAsString() {
string s;
for (int i = 0; i < new_Character.size(); i++) {
s += new_Character.at(i).GetC();
}
return s;
}