I wrote my string class. The code works, but could anyone tell if I am doing anything wrong?
It is an exercise from the "Accelerated c++" book:
Implement the Str class, but choose an implementation strategy that requires that the class manage the storage itself. For example, you might store an array of char and a length. Consider what implications this change in design has for copy control. Also consider the cost of using Vec, (e.g., in storage overhead). Implement the c_str, data, and copy functions.
#ifndef STRINGCLASS_STR_H
#define STRINGCLASS_STR_H
#include <memory>
#include <cstring>
#include <iostream>
using std::strlen;
using std::allocator;
class Str {
friend std::ostream &operator<<(std::ostream &, const Str &);
friend std::istream &operator>>(std::istream &, Str &);
friend Str operator+(const Str &, const Str &);
public:
typedef char* iterator;
typedef size_t size_type;
Str() { }
Str(size_type n, char c) { create(n, c); }
Str(const char *s) { create(s); }
template<class In>
Str(In b, In e) {create(b,e); }
~Str() {
if (data) alloc.deallocate(data, length);
data = 0;
length = 0;
}
Str &operator+=(const Str &s) {
size_type new_length = s.length + length - 1; //remove 1 because of 2 nulls
char *new_data = alloc.allocate(new_length);
strcpy(new_data, data);
strcpy(new_data + length - 1, s.data); //overwrite null from s
data = new_data;
length = new_length;
return *this;
}
Str &operator=(const Str &rhs) {
if (&rhs != this) {
if (data) alloc.deallocate(data, length);
create(rhs.data);
}
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(){
char* result = alloc.allocate(length);
std::uninitialized_copy(data, data+length, result);
return result;
}
const char* rawdata(){
char* result = alloc.allocate(length-1);
std::uninitialized_copy(data, data+length-1, result);
return result;
}
void copy(char *p, size_type n){
if(n>length)
throw std::out_of_range("Out of range");
std::copy(data, data+n, p);
}
char* begin(){return data;};
char* end(){ return data+length;};
private:
char *data;
allocator<char> alloc;
size_type length;
void create(size_type n, char c) {
length = n + 1;
data = alloc.allocate(length);
std::uninitialized_fill(data, data + length - 1, c);
alloc.construct(data + length - 1, '\0');
}
void create(const char *s) {
length = strlen(s) + 1;
data = alloc.allocate(length);
strcpy(data, s);
alloc.construct(data + length - 1, '\0');
}
template<class In>
void create(In b, In e){
length = e - b + 1;
data = alloc.allocate(length);
size_type i = 0;
while (b != e) {
data[i++] = *(b++);
}
alloc.construct(data + length - 1, '\0');
}
};
std::istream &operator>>(std::istream &is, Str &s) {
std::vector<char> buf;
char c;
while (is.get(c) && isspace(c)) { ;
}
if (is) {
do buf.push_back(c);
while (is.get(c) && !isspace(c));
if (is)
is.unget();
}
s.create(buf.begin(), buf.end());
return is;
}
std::ostream &operator<<(std::ostream &os, const Str &s) {
os << s.data;
return os;
}
Str operator+(const Str &s, const Str &t) {
Str res;
res.length = s.length + t.length - 1;
res.data = res.alloc.allocate(res.length);
strcpy(res.data, s.data);
strcpy(res.data + s.length - 1, t.data);
return res;
}
#endif //STRINGCLASS_STR_H
This is 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;
Str t = "World";
cout<<s+t<<endl;
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];
u.copy(copied, 4);
cout<<copied<<endl;
return 0;
}
c_str()
andrawdata()
return allocated copies of the string, but do not retain those references. \$\endgroup\$